From ac5860d10cba67eab9b8d9e3d111625f203397b7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 6 Aug 2022 14:54:26 +0100 Subject: [PATCH 01/57] feat(arabot): add create a new vc for joining and delete vc when leaving and give the user non vegan role --- package-lock.json | 2 +- package.json | 2 +- src/listeners/verification/config.ts | 23 ++++ src/listeners/verification/joinVC.ts | 146 ++++++++++++++++++++++++++ src/listeners/verification/leaveVC.ts | 73 +++++++++++++ 5 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 src/listeners/verification/config.ts create mode 100644 src/listeners/verification/joinVC.ts create mode 100644 src/listeners/verification/leaveVC.ts diff --git a/package-lock.json b/package-lock.json index 4862174..001d2a9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@types/node": "^18.0.3", "cron": "^2.1.0", "discord-api-types": "^0.33.3", - "discord.js": "^13.8.1", + "discord.js": "^13.9.2", "dotenv": "^16.0.1", "prisma": "^4.0.0", "ts-node": "^10.8.2", diff --git a/package.json b/package.json index ab2e5f7..f3fd6b3 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@types/node": "^18.0.3", "cron": "^2.1.0", "discord-api-types": "^0.33.3", - "discord.js": "^13.8.1", + "discord.js": "^13.9.2", "dotenv": "^16.0.1", "prisma": "^4.0.0", "ts-node": "^10.8.2", diff --git a/src/listeners/verification/config.ts b/src/listeners/verification/config.ts new file mode 100644 index 0000000..144b65e --- /dev/null +++ b/src/listeners/verification/config.ts @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +// This file is the configuration file for the verification system + +// The maximum number of Verification Voice Channels at a time +export const maxVCs = 10; diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts new file mode 100644 index 0000000..c1bfbee --- /dev/null +++ b/src/listeners/verification/joinVC.ts @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { container, Listener } from '@sapphire/framework'; +import type { + TextChannel, VoiceChannel, CategoryChannel, VoiceState, +} from 'discord.js'; +import { maxVCs } from './config'; + +export class VerificationJoinVCListener extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + event: 'voiceStateUpdate', + }); + } + + public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id === '999431677006860409' // ID for Verification category + || newState.channel?.parent?.id !== '999431677006860409' // ID for Verification category + ) { + return; + } + + // Checks if a verifier has joined + if (newState.channel.members.size === 2) { + await newState.channel!.permissionOverwrites.set([ + { + id: '999431675081666597', // verify-as-vegan + allow: ['SEND_MESSAGES'], + }, + ]); + return; + } + + // Checks if there is more than one person who has joined or if the channel has members + if (newState.channel.members.size !== 1 + || !newState.channel.members.has(newState.member!.id)) { + return; + } + + // TODO add database information + + const channel = newState.channel!; + const { client } = container; + const guild = client.guilds.cache.get(newState.guild.id)!; + const currentChannel = guild.channels.cache.get(newState.channel.id) as VoiceChannel; + + // Check if the user has the verifiers role + if (newState.member?.roles.cache.has('999431675123597406')) { + await channel.setName('Verifiers Only'); + } else { + await channel.setName(`Verification - ${newState.member?.displayName}`); + await currentChannel.send(`Hiya ${newState.member?.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); + } + + // Check how many voice channels there are + const category = guild.channels.cache.get('999431677006860409') as CategoryChannel; + const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + + // Create a new channel for others to join + + // TODO add a global max size + // Checks if there are more than 10 voice channels + if (listVoiceChannels.size > maxVCs - 1) { + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: '999431677006860409', // Verification topic + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: '999431675081666597', // verify-as-vegan + allow: ['VIEW_CHANNEL'], + deny: ['CONNECT'], + }, + { + id: '999431675123597406', // Verifiers + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } else { + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: '999431677006860409', // Verification topic + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: '999431675081666597', // verify-as-vegan + allow: ['VIEW_CHANNEL'], + }, + { + id: '999431675123597406', // Verifiers + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + + // Change permissions to join the current channel + await currentChannel.permissionOverwrites.set([ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: '999431675081666597', // verify-as-vegan + deny: ['VIEW_CHANNEL'], + }, + { + id: newState.member!.id, + allow: ['VIEW_CHANNEL'], + }, + ]); + await currentChannel.setUserLimit(0); + + // Send a message that someone wants to be verified + const verifyChannel = client.channels.cache.get('999431677006860411') as TextChannel; // Verifiers channel + verifyChannel.send(`${newState.member?.user} wants to be verified in ${newState.channel}`); + } +} diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts new file mode 100644 index 0000000..55fbd1c --- /dev/null +++ b/src/listeners/verification/leaveVC.ts @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { container, Listener } from '@sapphire/framework'; +import type { VoiceState, CategoryChannel, VoiceChannel } from 'discord.js'; +import { maxVCs } from './config'; + +export class VerificationLeaveVCListener extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + event: 'voiceStateUpdate', + }); + } + + public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id !== '999431677006860409' // ID for Verification category + || newState.channel?.parent?.id === '999431677006860409' // ID for Verification category + || oldState.channel.members.size > 0 + ) { + return; + } + + // Allow more people to join VC if there are less than 10 VCs + const { client } = container; + const guild = client.guilds.cache.get(newState.guild.id)!; + const user = guild.members.cache.get(oldState.member!.id)!; + + // Remove verify as vegan and give non vegan role + await user.roles.remove('999431675081666597'); // Verify-as-vegan + await user.roles.add('999431675081666598'); // Not vegan + + // Delete the channel + await oldState.channel!.delete(); + + // Check how many voice channels there are + const category = guild.channels.cache.get('999431677006860409') as CategoryChannel; + const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + + console.log(listVoiceChannels.size); + // If there are less than 10, stop + if (listVoiceChannels.size < maxVCs) { + return; + } + + const verification = listVoiceChannels.last() as VoiceChannel; + console.log(verification?.name); + + await verification!.permissionOverwrites.set([ + { + id: '999431675081666597', // verify-as-vegan + allow: ['VIEW_CHANNEL'], + }, + ]); + } +} From 7a2543cea18fcfbc02ff233e9c161470976fb1ee Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 6 Aug 2022 15:08:18 +0100 Subject: [PATCH 02/57] feat(docker): add automatic restart on failure to bot --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index af5be13..7c37a3d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,7 @@ services: dockerfile: Dockerfile depends_on: - postgres + restart: on-failure env_file: - .env From c0a0e105476d26d3afd76b981cff16c4ba62bbb8 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 6 Aug 2022 16:46:34 +0100 Subject: [PATCH 03/57] feat(database): add update user function --- prisma/schema.prisma | 4 -- src/utils/dbExistingUser.ts | 79 ++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 22 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 796dbdd..11506a2 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -27,10 +27,6 @@ datasource db { model User { id String @id @db.VarChar(255) - level Int @default(0) - xp Int @default(0) - balance Int @default(0) - lastDaily DateTime? vegan Boolean @default(false) trusted Boolean @default(false) activist Boolean @default(false) diff --git a/src/utils/dbExistingUser.ts b/src/utils/dbExistingUser.ts index 14b76d8..b4aa36f 100644 --- a/src/utils/dbExistingUser.ts +++ b/src/utils/dbExistingUser.ts @@ -17,7 +17,7 @@ along with this program. If not, see . */ -import type { GuildMember } from 'discord.js'; +import type { GuildMember, GuildMemberRoleManager } from 'discord.js'; import { PrismaClient } from '@prisma/client'; import { IDs } from './ids'; @@ -43,6 +43,22 @@ export async function userExists(user: GuildMember) { return false; } +function getRoles(roles: GuildMemberRoleManager) { + // Checks what roles the user has + const rolesDict = { + vegan: roles.cache.has(IDs.roles.vegan.vegan), + activist: roles.cache.has(IDs.roles.vegan.activist), + plus: roles.cache.has(IDs.roles.vegan.plus), + notVegan: roles.cache.has(IDs.roles.nonvegan.nonvegan), + vegCurious: roles.cache.has(IDs.roles.nonvegan.vegCurious), + convinced: roles.cache.has(IDs.roles.nonvegan.convinced), + trusted: roles.cache.has(IDs.roles.trusted), + muted: roles.cache.has(IDs.roles.restrictions.muted), + }; + + return rolesDict; +} + // Adds the user to the database if they were already on the server before the bot/database export async function addExistingUser(user: GuildMember) { // Initialises Prisma Client @@ -60,28 +76,55 @@ export async function addExistingUser(user: GuildMember) { return; } - // Checks what roles the user has - const hasVegan = user.roles.cache.has(IDs.roles.vegan.vegan); - const hasActivist = user.roles.cache.has(IDs.roles.vegan.activist); - const hasPlus = user.roles.cache.has(IDs.roles.vegan.plus); - const hasNotVegan = user.roles.cache.has(IDs.roles.nonvegan.nonvegan); - const hasVegCurious = user.roles.cache.has(IDs.roles.nonvegan.vegCurious); - const hasConvinced = user.roles.cache.has(IDs.roles.nonvegan.convinced); - const hasTrusted = user.roles.cache.has(IDs.roles.trusted); - const hasMuted = user.roles.cache.has(IDs.roles.restrictions.muted); + // Parse all the roles into a dictionary + const roles = getRoles(user.roles); // Create the user in the database await prisma.user.create({ data: { id: user.id, - vegan: hasVegan, - trusted: hasTrusted, - activist: hasActivist, - plus: hasPlus, - notVegan: hasNotVegan, - vegCurious: hasVegCurious, - convinced: hasConvinced, - muted: hasMuted, + vegan: roles.vegan, + trusted: roles.trusted, + activist: roles.activist, + plus: roles.plus, + notVegan: roles.notVegan, + vegCurious: roles.vegCurious, + convinced: roles.convinced, + muted: roles.muted, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +export async function updateUser(user: GuildMember) { + // Check if the user is already on the database + if (!(await userExists(user))) { + await addExistingUser(user); + return; + } + + // Parse all the roles into a dictionary + const roles = getRoles(user.roles); + + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.user.update({ + where: { + id: user.id, + }, + data: { + id: user.id, + vegan: roles.vegan, + trusted: roles.trusted, + activist: roles.activist, + plus: roles.plus, + notVegan: roles.notVegan, + vegCurious: roles.vegCurious, + convinced: roles.convinced, + muted: roles.muted, }, }); From 0ebf6af08926eb73a7fe92bddf2ad3dbc512a2cc Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 8 Aug 2022 01:45:34 +0100 Subject: [PATCH 04/57] ci(docker): remove .env file from being in the container --- .dockerignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.dockerignore b/.dockerignore index 14c1566..2a06ca8 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,3 +3,4 @@ dist node_modules tsconfig.tsbuildinfo npm-debug.log +.env From e4cb0bdfdc39ccfa15f2845602560ab404e3c59b Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 8 Aug 2022 01:59:07 +0100 Subject: [PATCH 05/57] feat(verification): add a check if the joinable vc will be deleted --- src/listeners/verification/joinVC.ts | 7 ++--- src/listeners/verification/leaveVC.ts | 41 ++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index c1bfbee..bcac8eb 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -64,10 +64,10 @@ export class VerificationJoinVCListener extends Listener { const currentChannel = guild.channels.cache.get(newState.channel.id) as VoiceChannel; // Check if the user has the verifiers role - if (newState.member?.roles.cache.has('999431675123597406')) { - await channel.setName('Verifiers Only'); + if (newState.member?.roles.cache.has('999431675123597406')) { // TODO add check if they are trial-verifiers + await channel.setName('Verifier Meeting'); } else { - await channel.setName(`Verification - ${newState.member?.displayName}`); + await channel.setName(`${newState.member?.displayName} - Verification`); await currentChannel.send(`Hiya ${newState.member?.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); } @@ -77,7 +77,6 @@ export class VerificationJoinVCListener extends Listener { // Create a new channel for others to join - // TODO add a global max size // Checks if there are more than 10 voice channels if (listVoiceChannels.size > maxVCs - 1) { await guild.channels.create('Verification', { diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 55fbd1c..8caf2f9 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -44,24 +44,51 @@ export class VerificationLeaveVCListener extends Listener { const user = guild.members.cache.get(oldState.member!.id)!; // Remove verify as vegan and give non vegan role - await user.roles.remove('999431675081666597'); // Verify-as-vegan - await user.roles.add('999431675081666598'); // Not vegan - - // Delete the channel - await oldState.channel!.delete(); + if (!user.roles.cache.has('999431675098447937')) { // If the user does not have vegan role + await user.roles.remove('999431675081666597'); // Verify-as-vegan + await user.roles.add('999431675081666598'); // Not vegan + } // Check how many voice channels there are const category = guild.channels.cache.get('999431677006860409') as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); - console.log(listVoiceChannels.size); + // Check that it is not deleting the 'Verification' channel (in case bot crashes) + if (oldState.channel.name !== 'Verification') { + // Delete the channel + await oldState.channel!.delete(); + } + + // If there are no VCs left in verification after having the channel deleted + if (listVoiceChannels.size === 0) { + // Create a verification channel + await guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: '999431677006860409', // Verification topic + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: '999431675081666597', // verify-as-vegan + allow: ['VIEW_CHANNEL'], + }, + { + id: '999431675123597406', // Verifiers + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + // If there are less than 10, stop if (listVoiceChannels.size < maxVCs) { return; } const verification = listVoiceChannels.last() as VoiceChannel; - console.log(verification?.name); await verification!.permissionOverwrites.set([ { From 4e856913e9dba4abe77b74b907be1b046dab1a29 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 10 Aug 2022 04:37:28 +0100 Subject: [PATCH 06/57] feat(arabot): dantas is literally 1984 --- src/commands/fun/1984.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/commands/fun/1984.ts b/src/commands/fun/1984.ts index c75aa01..439916b 100644 --- a/src/commands/fun/1984.ts +++ b/src/commands/fun/1984.ts @@ -51,7 +51,9 @@ export class N1984Command extends Command { const memberGuildMember = interaction.guild!.members.cache.get(member.id)!; // Creates the embed for the 1984 reaction - const random1984 = N1984[Math.floor(Math.random() * N1984.length)]; + // Add a 1 in 1000 chance of Dantas literally making ARA 1984 + const random1984 = Math.random() < 0.001 ? 'https://tenor.com/view/arthuria-dantas-dancing-dantas-woke-weebs-gif-18773803' + : N1984[Math.floor(Math.random() * N1984.length)]; const n1984Embed = new MessageEmbed() .setColor('#ffffff') .setTitle(`${memberGuildMember.displayName} is happy!`) From 31199d9cd5c5e43bf7126bf1d59389bef5828984 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 10 Aug 2022 05:20:04 +0100 Subject: [PATCH 07/57] feat(arabot): add dev ids in development mode --- .env.example | 1 + src/utils/devIDs.ts | 71 +++++++++++++++++++++++++++++++++++++++++++++ src/utils/ids.ts | 14 +++++++-- 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 src/utils/devIDs.ts diff --git a/.env.example b/.env.example index 0d68079..d64f24e 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ DISCORD_TOKEN= # Bot token from: https://discord.com/developers/ # Configuration DEFAULT_PREFIX= # Prefix used to run commands in Discord +DEVELOPMENT= # (true/false) Enables developer mode # Docker POSTGRES_USER=USERNAME diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts new file mode 100644 index 0000000..d259411 --- /dev/null +++ b/src/utils/devIDs.ts @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +export const devIDs = { + roles: { + trusted: '999431675081666599', + nonvegan: { + nonvegan: '999431675081666598', + vegCurious: '999431675098447932', + convinced: '999431675098447933', + }, + vegan: { + vegan: '999431675098447937', + activist: '999431675098447934', + plus: '999431675010359460', + }, + restrictions: { + sus: '999431674997788673', + muted: '999431675123597402', + restricted1: '999431674997788677', + restricted2: '999431674997788676', + restricted3: '999431674997788675', + restricted4: '999431674997788674', + }, + staff: { + coordinator: '999431675165556822', + devCoordinator: '999431675165556818', + mentorCoordinator: '999431675140382809', + verifierCoordinator: '999431675140382810', + restricted: '999431675123597407', + moderator: '999431675123597408', + verifier: '999431675123597406', + }, + patron: '999431675098447935', + patreon: '999431675098447936', + verifyingAsVegan: '999431675081666597', + }, + channels: { + staff: { + coordinators: '999431676058927254', + standup: '999431676289622183', + }, + diversity: { + women: '999431679053660187', + lgbtqia: '999431679053660188', + potgm: '999431679053660189', + disabilities: '999431679527628810', + }, + }, + categories: { + diversity: '999431679053660185', + }, +}; + +export default devIDs; diff --git a/src/utils/ids.ts b/src/utils/ids.ts index e46a83c..90755c4 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -17,7 +17,10 @@ along with this program. If not, see . */ -const IDs = { +// eslint-disable-next-line import/extensions +import devIDs from './devIDs'; + +let IDs = { roles: { trusted: '731563158011117590', nonvegan: { @@ -68,4 +71,11 @@ const IDs = { }, }; -export { IDs }; +require('dotenv').config(); + +// Check if the bot is in development mode +if (process.env.DEVELOPMENT === 'true') { + IDs = devIDs; +} + +export default { IDs }; From ed5327aae2f3a91840f88b48829a1bee10c9d0a7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 10 Aug 2022 05:34:26 +0100 Subject: [PATCH 08/57] feat(verification): add IDs from utils --- src/listeners/verification/joinVC.ts | 31 ++++++++++++++------------- src/listeners/verification/leaveVC.ts | 23 ++++++++++---------- src/utils/devIDs.ts | 2 ++ src/utils/ids.ts | 4 +++- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index bcac8eb..267657f 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -21,7 +21,8 @@ import { container, Listener } from '@sapphire/framework'; import type { TextChannel, VoiceChannel, CategoryChannel, VoiceState, } from 'discord.js'; -import { maxVCs } from './config'; +import { maxVCs } from '../../utils/verificationConfig'; +import IDs from '../../utils/ids'; export class VerificationJoinVCListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { @@ -33,8 +34,8 @@ export class VerificationJoinVCListener extends Listener { public async run(oldState: VoiceState, newState: VoiceState) { // If the event was not a user joining the channel - if (oldState.channel?.parent?.id === '999431677006860409' // ID for Verification category - || newState.channel?.parent?.id !== '999431677006860409' // ID for Verification category + if (oldState.channel?.parent?.id === IDs.categories.verification + || newState.channel?.parent?.id !== IDs.categories.verification ) { return; } @@ -43,7 +44,7 @@ export class VerificationJoinVCListener extends Listener { if (newState.channel.members.size === 2) { await newState.channel!.permissionOverwrites.set([ { - id: '999431675081666597', // verify-as-vegan + id: IDs.categories.verification, allow: ['SEND_MESSAGES'], }, ]); @@ -64,7 +65,7 @@ export class VerificationJoinVCListener extends Listener { const currentChannel = guild.channels.cache.get(newState.channel.id) as VoiceChannel; // Check if the user has the verifiers role - if (newState.member?.roles.cache.has('999431675123597406')) { // TODO add check if they are trial-verifiers + if (newState.member?.roles.cache.has(IDs.roles.staff.verifier)) { // TODO add check if they are trial-verifiers await channel.setName('Verifier Meeting'); } else { await channel.setName(`${newState.member?.displayName} - Verification`); @@ -72,7 +73,7 @@ export class VerificationJoinVCListener extends Listener { } // Check how many voice channels there are - const category = guild.channels.cache.get('999431677006860409') as CategoryChannel; + const category = guild.channels.cache.get(IDs.categories.verification) as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); // Create a new channel for others to join @@ -81,7 +82,7 @@ export class VerificationJoinVCListener extends Listener { if (listVoiceChannels.size > maxVCs - 1) { await guild.channels.create('Verification', { type: 'GUILD_VOICE', - parent: '999431677006860409', // Verification topic + parent: IDs.categories.verification, userLimit: 1, permissionOverwrites: [ { @@ -89,12 +90,12 @@ export class VerificationJoinVCListener extends Listener { deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, { - id: '999431675081666597', // verify-as-vegan + id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], deny: ['CONNECT'], }, { - id: '999431675123597406', // Verifiers + id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, ], @@ -102,7 +103,7 @@ export class VerificationJoinVCListener extends Listener { } else { await guild.channels.create('Verification', { type: 'GUILD_VOICE', - parent: '999431677006860409', // Verification topic + parent: IDs.categories.verification, userLimit: 1, permissionOverwrites: [ { @@ -110,11 +111,11 @@ export class VerificationJoinVCListener extends Listener { deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, { - id: '999431675081666597', // verify-as-vegan + id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], }, { - id: '999431675123597406', // Verifiers + id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, ], @@ -128,7 +129,7 @@ export class VerificationJoinVCListener extends Listener { deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, { - id: '999431675081666597', // verify-as-vegan + id: IDs.roles.verifyingAsVegan, deny: ['VIEW_CHANNEL'], }, { @@ -139,7 +140,7 @@ export class VerificationJoinVCListener extends Listener { await currentChannel.setUserLimit(0); // Send a message that someone wants to be verified - const verifyChannel = client.channels.cache.get('999431677006860411') as TextChannel; // Verifiers channel - verifyChannel.send(`${newState.member?.user} wants to be verified in ${newState.channel}`); + const verifyChannel = client.channels.cache.get(IDs.channels.staff.verifiers) as TextChannel; + await verifyChannel.send(`${newState.member?.user} wants to be verified in ${newState.channel}`); } } diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 8caf2f9..5fee394 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -19,7 +19,8 @@ import { container, Listener } from '@sapphire/framework'; import type { VoiceState, CategoryChannel, VoiceChannel } from 'discord.js'; -import { maxVCs } from './config'; +import { maxVCs } from '../../utils/verificationConfig'; +import IDs from '../../utils/ids'; export class VerificationLeaveVCListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { @@ -31,8 +32,8 @@ export class VerificationLeaveVCListener extends Listener { public async run(oldState: VoiceState, newState: VoiceState) { // If the event was not a user joining the channel - if (oldState.channel?.parent?.id !== '999431677006860409' // ID for Verification category - || newState.channel?.parent?.id === '999431677006860409' // ID for Verification category + if (oldState.channel?.parent?.id !== IDs.categories.verification + || newState.channel?.parent?.id === IDs.categories.verification || oldState.channel.members.size > 0 ) { return; @@ -44,13 +45,13 @@ export class VerificationLeaveVCListener extends Listener { const user = guild.members.cache.get(oldState.member!.id)!; // Remove verify as vegan and give non vegan role - if (!user.roles.cache.has('999431675098447937')) { // If the user does not have vegan role - await user.roles.remove('999431675081666597'); // Verify-as-vegan - await user.roles.add('999431675081666598'); // Not vegan + if (!user.roles.cache.has(IDs.roles.vegan.vegan)) { + await user.roles.remove(IDs.roles.verifyingAsVegan); + await user.roles.add(IDs.roles.nonvegan.nonvegan); } // Check how many voice channels there are - const category = guild.channels.cache.get('999431677006860409') as CategoryChannel; + const category = guild.channels.cache.get(IDs.categories.verification) as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); // Check that it is not deleting the 'Verification' channel (in case bot crashes) @@ -64,7 +65,7 @@ export class VerificationLeaveVCListener extends Listener { // Create a verification channel await guild.channels.create('Verification', { type: 'GUILD_VOICE', - parent: '999431677006860409', // Verification topic + parent: IDs.categories.verification, userLimit: 1, permissionOverwrites: [ { @@ -72,11 +73,11 @@ export class VerificationLeaveVCListener extends Listener { deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, { - id: '999431675081666597', // verify-as-vegan + id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], }, { - id: '999431675123597406', // Verifiers + id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, ], @@ -92,7 +93,7 @@ export class VerificationLeaveVCListener extends Listener { await verification!.permissionOverwrites.set([ { - id: '999431675081666597', // verify-as-vegan + id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], }, ]); diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index d259411..74dbf5b 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -55,6 +55,7 @@ export const devIDs = { staff: { coordinators: '999431676058927254', standup: '999431676289622183', + verifiers: '999431677006860411', }, diversity: { women: '999431679053660187', @@ -64,6 +65,7 @@ export const devIDs = { }, }, categories: { + verification: '999431677006860409', diversity: '999431679053660185', }, }; diff --git a/src/utils/ids.ts b/src/utils/ids.ts index 90755c4..153fa9f 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -58,6 +58,7 @@ let IDs = { staff: { coordinators: '989249700353953843', standup: '996009201237233684', + verifiers: '873215538627756072', }, diversity: { women: '938808963544285324', @@ -67,6 +68,7 @@ let IDs = { }, }, categories: { + verification: '797505409073676299', diversity: '933078380394459146', }, }; @@ -78,4 +80,4 @@ if (process.env.DEVELOPMENT === 'true') { IDs = devIDs; } -export default { IDs }; +export default IDs; From f0b0408a71c3edb8e3295575fae493d3a70449e2 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 10 Aug 2022 05:38:18 +0100 Subject: [PATCH 09/57] feat(arabot): update IDs to be able to switch between development IDs and normal IDs --- src/commands/mod/diversityToggleOpen.ts | 2 +- src/commands/roles/vegcurious.ts | 2 +- src/commands/verification/purgeVerifying.ts | 2 +- src/preconditions/CoordinatorOnly.ts | 2 +- src/preconditions/DevCoordinatorOnly.ts | 2 +- src/preconditions/DiversityCoordinatorOnly.ts | 2 +- src/preconditions/MentorCoordinatorOnly.ts | 2 +- src/preconditions/ModOnly.ts | 2 +- src/preconditions/PatreonOnly.ts | 2 +- src/preconditions/VerifierCoordinatorOnly.ts | 2 +- src/preconditions/VerifierOnly.ts | 2 +- src/schedules/standup.ts | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/commands/mod/diversityToggleOpen.ts b/src/commands/mod/diversityToggleOpen.ts index f132aec..c1f564c 100644 --- a/src/commands/mod/diversityToggleOpen.ts +++ b/src/commands/mod/diversityToggleOpen.ts @@ -19,7 +19,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import type { TextChannel } from 'discord.js'; -import { IDs } from '../../utils/ids'; +import IDs from '../../utils/ids'; export class ToggleOpenCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { diff --git a/src/commands/roles/vegcurious.ts b/src/commands/roles/vegcurious.ts index 58c276b..7832fe1 100644 --- a/src/commands/roles/vegcurious.ts +++ b/src/commands/roles/vegcurious.ts @@ -18,7 +18,7 @@ */ import { Command, RegisterBehavior } from '@sapphire/framework'; -import { IDs } from '../../utils/ids'; +import IDs from '../../utils/ids'; export class VegCuriousCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { diff --git a/src/commands/verification/purgeVerifying.ts b/src/commands/verification/purgeVerifying.ts index 4ffb6ce..50c883f 100644 --- a/src/commands/verification/purgeVerifying.ts +++ b/src/commands/verification/purgeVerifying.ts @@ -19,7 +19,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; -import { IDs } from '../../utils/ids'; +import IDs from '../../utils/ids'; export class purgeVerifyingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { diff --git a/src/preconditions/CoordinatorOnly.ts b/src/preconditions/CoordinatorOnly.ts index 90cbf55..726a881 100644 --- a/src/preconditions/CoordinatorOnly.ts +++ b/src/preconditions/CoordinatorOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class CoordinatorOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/DevCoordinatorOnly.ts b/src/preconditions/DevCoordinatorOnly.ts index 6d752e7..13989cd 100644 --- a/src/preconditions/DevCoordinatorOnly.ts +++ b/src/preconditions/DevCoordinatorOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class DevCoordinatorOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/DiversityCoordinatorOnly.ts b/src/preconditions/DiversityCoordinatorOnly.ts index 55e2b13..acf328f 100644 --- a/src/preconditions/DiversityCoordinatorOnly.ts +++ b/src/preconditions/DiversityCoordinatorOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class DiversityCoordinatorOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/MentorCoordinatorOnly.ts b/src/preconditions/MentorCoordinatorOnly.ts index d446395..514ab54 100644 --- a/src/preconditions/MentorCoordinatorOnly.ts +++ b/src/preconditions/MentorCoordinatorOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class MentorCoordinatorOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/ModOnly.ts b/src/preconditions/ModOnly.ts index c781a7c..8756ad6 100644 --- a/src/preconditions/ModOnly.ts +++ b/src/preconditions/ModOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class ModOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/PatreonOnly.ts b/src/preconditions/PatreonOnly.ts index 31c78ca..d44a2b0 100644 --- a/src/preconditions/PatreonOnly.ts +++ b/src/preconditions/PatreonOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class PatreonOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/VerifierCoordinatorOnly.ts b/src/preconditions/VerifierCoordinatorOnly.ts index 16fb625..61c270a 100644 --- a/src/preconditions/VerifierCoordinatorOnly.ts +++ b/src/preconditions/VerifierCoordinatorOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class VerifierCoordinatorOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/preconditions/VerifierOnly.ts b/src/preconditions/VerifierOnly.ts index 108f034..b14a267 100644 --- a/src/preconditions/VerifierOnly.ts +++ b/src/preconditions/VerifierOnly.ts @@ -19,7 +19,7 @@ import { AllFlowsPrecondition } from '@sapphire/framework'; import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; import type { GuildMember } from 'discord.js'; export class VerifierOnlyPrecondition extends AllFlowsPrecondition { diff --git a/src/schedules/standup.ts b/src/schedules/standup.ts index fd89e4e..1b64d68 100644 --- a/src/schedules/standup.ts +++ b/src/schedules/standup.ts @@ -19,7 +19,7 @@ import { container } from '@sapphire/framework'; import type { TextChannel } from 'discord.js'; -import { IDs } from '../utils/ids'; +import IDs from '../utils/ids'; export async function standupRun() { const { client } = container; From 2abc957284d2e78757f0c773c847bc44fb13df81 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 12 Aug 2022 00:50:12 +0100 Subject: [PATCH 10/57] feat(eslint): add airbnb-typescript to eslint --- .eslintrc.json | 6 ++++-- package-lock.json | 25 +++++++++++++++++++++++++ package.json | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f1a2f83..06613cf 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,12 +4,14 @@ "es2021": true }, "extends": [ - "airbnb-base" + "airbnb-base", + "airbnb-typescript/base" ], "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaVersion": "latest", - "sourceType": "module" + "sourceType": "module", + "project": "tsconfig.json" }, "plugins": [ "@typescript-eslint" diff --git a/package-lock.json b/package-lock.json index 001d2a9..1e5eea2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "@typescript-eslint/parser": "^5.30.7", "eslint": "^8.20.0", "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.0.0", "eslint-plugin-import": "^2.26.0" } }, @@ -1186,6 +1187,21 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-config-airbnb-typescript": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz", + "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==", + "dev": true, + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", @@ -3940,6 +3956,15 @@ } } }, + "eslint-config-airbnb-typescript": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz", + "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==", + "dev": true, + "requires": { + "eslint-config-airbnb-base": "^15.0.0" + } + }, "eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", diff --git a/package.json b/package.json index f3fd6b3..c9103dc 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@typescript-eslint/parser": "^5.30.7", "eslint": "^8.20.0", "eslint-config-airbnb-base": "^15.0.0", + "eslint-config-airbnb-typescript": "^17.0.0", "eslint-plugin-import": "^2.26.0" } } From 0d571dd9233e80572d2f3e7aeae7ee639fa8e8a9 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 18 Aug 2022 03:20:49 +0100 Subject: [PATCH 11/57] feat(arabot): add text channel to verification --- src/listeners/verification/joinVC.ts | 71 ++++++-- src/listeners/verification/leaveVC.ts | 50 +++++- src/utils/{ => database}/dbExistingUser.ts | 24 ++- src/utils/database/verification.ts | 153 ++++++++++++++++++ src/utils/devIDs.ts | 3 + src/utils/ids.ts | 2 + .../config.ts => utils/verificationConfig.ts} | 0 7 files changed, 284 insertions(+), 19 deletions(-) rename src/utils/{ => database}/dbExistingUser.ts (89%) create mode 100644 src/utils/database/verification.ts rename src/{listeners/verification/config.ts => utils/verificationConfig.ts} (100%) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 267657f..35cf9cd 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -18,13 +18,12 @@ */ import { container, Listener } from '@sapphire/framework'; -import type { - TextChannel, VoiceChannel, CategoryChannel, VoiceState, -} from 'discord.js'; +import type { VoiceChannel, CategoryChannel, VoiceState } from 'discord.js'; import { maxVCs } from '../../utils/verificationConfig'; +import { joinVerification, startVerification } from '../../utils/database/verification'; import IDs from '../../utils/ids'; -export class VerificationJoinVCListener extends Listener { +export default class VerificationJoinVCListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { super(context, { ...options, @@ -40,6 +39,9 @@ export class VerificationJoinVCListener extends Listener { return; } + // Variable if this channel is a Verifiers only VC + let verifier = false; + // Checks if a verifier has joined if (newState.channel.members.size === 2) { await newState.channel!.permissionOverwrites.set([ @@ -51,31 +53,72 @@ export class VerificationJoinVCListener extends Listener { return; } + // Check if a verifier joined a verification VC and update database + if (newState.channel.members.size === 2) { + if (!newState.channel.name.includes(' - Verification')) { + return; + } + + await startVerification(newState.member!, newState.channelId!); + return; + } + // Checks if there is more than one person who has joined or if the channel has members if (newState.channel.members.size !== 1 || !newState.channel.members.has(newState.member!.id)) { return; } - // TODO add database information - const channel = newState.channel!; const { client } = container; const guild = client.guilds.cache.get(newState.guild.id)!; - const currentChannel = guild.channels.cache.get(newState.channel.id) as VoiceChannel; + const currentChannel = guild.channels.cache.get(newState.channelId!) as VoiceChannel; // Check if the user has the verifiers role - if (newState.member?.roles.cache.has(IDs.roles.staff.verifier)) { // TODO add check if they are trial-verifiers + if (newState.member?.roles.cache.has(IDs.roles.staff.verifier) + || newState.member?.roles.cache.has(IDs.roles.staff.trialVerifier)) { await channel.setName('Verifier Meeting'); + verifier = true; } else { await channel.setName(`${newState.member?.displayName} - Verification`); await currentChannel.send(`Hiya ${newState.member?.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); + // Adds to the database that the user joined verification + await joinVerification(newState.member!, channel.id); } // Check how many voice channels there are const category = guild.channels.cache.get(IDs.categories.verification) as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + // Create a text channel for verifiers only + // Checks if there are more than 10 voice channels + if (!verifier) { + const verificationText = await guild.channels.create(`✅┃${newState.member?.displayName}-verification`, { + type: 'GUILD_TEXT', + topic: `Channel for verifiers only. ${newState.member?.id} (Please do not change this)`, + parent: IDs.categories.verification, + userLimit: 1, + permissionOverwrites: [ + { + id: guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + + // Send a message that someone wants to be verified + await verificationText.send(`${newState.member?.user} wants to be verified in ${newState.channel} + \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); + } + // Create a new channel for others to join // Checks if there are more than 10 voice channels @@ -89,6 +132,10 @@ export class VerificationJoinVCListener extends Listener { id: guild.roles.everyone, deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, { id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], @@ -110,6 +157,10 @@ export class VerificationJoinVCListener extends Listener { id: guild.roles.everyone, deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, { id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], @@ -138,9 +189,5 @@ export class VerificationJoinVCListener extends Listener { }, ]); await currentChannel.setUserLimit(0); - - // Send a message that someone wants to be verified - const verifyChannel = client.channels.cache.get(IDs.channels.staff.verifiers) as TextChannel; - await verifyChannel.send(`${newState.member?.user} wants to be verified in ${newState.channel}`); } } diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 5fee394..8a12996 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -18,8 +18,11 @@ */ import { container, Listener } from '@sapphire/framework'; -import type { VoiceState, CategoryChannel, VoiceChannel } from 'discord.js'; +import type { + VoiceState, CategoryChannel, VoiceChannel, TextChannel, +} from 'discord.js'; import { maxVCs } from '../../utils/verificationConfig'; +import { getUser } from '../../utils/database/verification'; import IDs from '../../utils/ids'; export class VerificationLeaveVCListener extends Listener { @@ -42,12 +45,30 @@ export class VerificationLeaveVCListener extends Listener { // Allow more people to join VC if there are less than 10 VCs const { client } = container; const guild = client.guilds.cache.get(newState.guild.id)!; - const user = guild.members.cache.get(oldState.member!.id)!; + let verifier = false; - // Remove verify as vegan and give non vegan role - if (!user.roles.cache.has(IDs.roles.vegan.vegan)) { - await user.roles.remove(IDs.roles.verifyingAsVegan); - await user.roles.add(IDs.roles.nonvegan.nonvegan); + // Get the user that was being verified + const userSnowflake = await getUser(oldState.channel.id); + if (userSnowflake === null) { + verifier = true; + } + + if (!verifier) { + console.log(userSnowflake); + const user = guild.members.cache.get(userSnowflake!)!; + + /* + // Add the user to the database if it's not a verifier meeting + if (!oldState.channel.name.includes(' - Verification')) { + await finishVerification(oldState.channelId!, true, true, false, false); + } + */ + + // Remove verify as vegan and give non vegan role + if (!user.roles.cache.has(IDs.roles.vegan.vegan)) { + await user.roles.remove(IDs.roles.verifyingAsVegan); + await user.roles.add(IDs.roles.nonvegan.nonvegan); + } } // Check how many voice channels there are @@ -60,6 +81,19 @@ export class VerificationLeaveVCListener extends Listener { await oldState.channel!.delete(); } + // Delete text channel + if (!verifier) { + // Gets a list of all the text channels in the verification category + const listTextChannels = category.children.filter((c) => c.type === 'GUILD_TEXT'); + listTextChannels.forEach((c) => { + const textChannel = c as TextChannel; + // Checks if the channel topic has the user's snowflake + if (textChannel.topic!.includes(userSnowflake!)) { + textChannel.delete(); + } + }); + } + // If there are no VCs left in verification after having the channel deleted if (listVoiceChannels.size === 0) { // Create a verification channel @@ -72,6 +106,10 @@ export class VerificationLeaveVCListener extends Listener { id: guild.roles.everyone, deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, { id: IDs.roles.verifyingAsVegan, allow: ['VIEW_CHANNEL'], diff --git a/src/utils/dbExistingUser.ts b/src/utils/database/dbExistingUser.ts similarity index 89% rename from src/utils/dbExistingUser.ts rename to src/utils/database/dbExistingUser.ts index b4aa36f..36f5c62 100644 --- a/src/utils/dbExistingUser.ts +++ b/src/utils/database/dbExistingUser.ts @@ -19,7 +19,7 @@ import type { GuildMember, GuildMemberRoleManager } from 'discord.js'; import { PrismaClient } from '@prisma/client'; -import { IDs } from './ids'; +import IDs from '../ids'; // Checks if the user exists on the database export async function userExists(user: GuildMember) { @@ -131,3 +131,25 @@ export async function updateUser(user: GuildMember) { // Close the database connection await prisma.$disconnect(); } + +export async function fetchRoles(user: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the user's roles + const roles = await prisma.user.findUnique({ + where: { + id: user, + }, + select: { + trusted: true, + plus: true, + vegCurious: true, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + return roles; +} diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts new file mode 100644 index 0000000..b7ff13b --- /dev/null +++ b/src/utils/database/verification.ts @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import type { GuildMember } from 'discord.js'; +import { PrismaClient } from '@prisma/client'; +import { updateUser } from './dbExistingUser'; + +export async function joinVerification(user: GuildMember, channelId: string) { + // Update the user on the database with the current roles they have + await updateUser(user); + + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.verify.create({ + data: { + id: channelId, + user: { + connect: { + id: user.id, + }, + }, + }, + }); + + // Close database connection + await prisma.$disconnect(); +} + +export async function startVerification(verifier: GuildMember, channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + await prisma.verify.update({ + where: { + id: channelId, + }, + data: { + verifier: { + connect: { + id: verifier.id, + }, + }, + startTime: new Date(), + }, + }); + + // Close database connection + await prisma.$disconnect(); +} + +export async function getUser(channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the snowflake of the user verifying + const user = await prisma.verify.findUnique({ + where: { + id: channelId, + }, + select: { + userId: true, + }, + }); + + // Close database connection + await prisma.$disconnect(); + + // Check the user could be found + if (user === null) { + return null; + } + + // Return the user's snowflake + return user.userId; +} + +export async function finishVerification( + channelId: string, + timedOut: boolean, + vegan: boolean, + text:boolean, + serverVegan: boolean, +) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + /* + const user = await prisma.verify.findUnique({ + where: { + id: channelId, + }, + select: { + userId: true, + }, + }); + */ + + // TODO potentially add an incomplete tracker? + await prisma.verify.update({ + where: { + id: channelId, + }, + data: { + timedOut, + vegan, + text, + serverVegan, + }, + }); + + // Close database connection + await prisma.$disconnect(); + + // TODO add a way to give roles back after adding the new verification + /* + const roles = await fetchRoles(user!.userId); + + if (roles === null) { + return; + } + + // Give roles to the user + const giveRoles = []; + if (roles.trusted) { + giveRoles.push(IDs.roles.trusted); + } + if (roles.plus) { + giveRoles.push(IDs.roles.vegan.plus); + } + if (roles.vegCurious) { + giveRoles.push(IDs.roles.nonvegan.vegCurious); + } + + await user.roles.add(giveRoles); + */ +} diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index 74dbf5b..6c35ede 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -41,15 +41,18 @@ export const devIDs = { staff: { coordinator: '999431675165556822', devCoordinator: '999431675165556818', + diversityCoordinator: '999431675140382808', mentorCoordinator: '999431675140382809', verifierCoordinator: '999431675140382810', restricted: '999431675123597407', moderator: '999431675123597408', verifier: '999431675123597406', + trialVerifier: '999431675123597405', }, patron: '999431675098447935', patreon: '999431675098447936', verifyingAsVegan: '999431675081666597', + verifyBlock: '1007477161835372574', }, channels: { staff: { diff --git a/src/utils/ids.ts b/src/utils/ids.ts index 5a310d3..cb0d40c 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -50,10 +50,12 @@ let IDs = { restricted: '851624392928264222', moderator: '826157475815489598', verifier: '871802735031373856', + trialVerifier: '982635638010572850', }, patron: '765370219207852055', patreon: '993848684640997406', verifyingAsVegan: '854725899576279060', + verifyBlock: '', }, channels: { staff: { diff --git a/src/listeners/verification/config.ts b/src/utils/verificationConfig.ts similarity index 100% rename from src/listeners/verification/config.ts rename to src/utils/verificationConfig.ts From 8d39539fef7b533024ee3c0adb49ff71677b1ca8 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 18 Aug 2022 03:52:35 +0100 Subject: [PATCH 12/57] refactor(arabot): add proper null checks --- src/listeners/verification/joinVC.ts | 75 ++++++++++++++++----------- src/listeners/verification/leaveVC.ts | 44 +++++++++++----- 2 files changed, 75 insertions(+), 44 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 35cf9cd..1d24df7 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -32,21 +32,42 @@ export default class VerificationJoinVCListener extends Listener { } public async run(oldState: VoiceState, newState: VoiceState) { + // Variable if this channel is a Verifiers only VC + let verifier = false; + + // Checks for not null + const { channel } = newState; + const { member } = newState; + const { client } = container; + const guild = client.guilds.cache.get(newState.guild.id); + + if (channel === null || member === null || guild === undefined) { + console.error('Verification channel not found'); + return; + } + + // Get current category and channel + const categoryGuild = guild.channels.cache.get(IDs.categories.verification); + const currentChannelGuild = guild.channels.cache.get(channel.id); + if (currentChannelGuild === undefined || categoryGuild === undefined) { + console.error('Verification channel not found'); + return; + } + const currentChannel = currentChannelGuild as VoiceChannel; + const category = categoryGuild as CategoryChannel; + // If the event was not a user joining the channel - if (oldState.channel?.parent?.id === IDs.categories.verification - || newState.channel?.parent?.id !== IDs.categories.verification + if (oldState.channel?.parent?.id === category.id + || channel.parent?.id !== category.id ) { return; } - // Variable if this channel is a Verifiers only VC - let verifier = false; - // Checks if a verifier has joined - if (newState.channel.members.size === 2) { + if (channel.members.size === 2) { await newState.channel!.permissionOverwrites.set([ { - id: IDs.categories.verification, + id: guild.roles.everyone, allow: ['SEND_MESSAGES'], }, ]); @@ -54,49 +75,43 @@ export default class VerificationJoinVCListener extends Listener { } // Check if a verifier joined a verification VC and update database - if (newState.channel.members.size === 2) { - if (!newState.channel.name.includes(' - Verification')) { + if (channel.members.size === 2) { + if (!channel.name.includes(' - Verification')) { return; } - await startVerification(newState.member!, newState.channelId!); + await startVerification(member, channel.id); return; } // Checks if there is more than one person who has joined or if the channel has members - if (newState.channel.members.size !== 1 - || !newState.channel.members.has(newState.member!.id)) { + if (channel.members.size !== 1 + || !channel.members.has(member.id)) { return; } - const channel = newState.channel!; - const { client } = container; - const guild = client.guilds.cache.get(newState.guild.id)!; - const currentChannel = guild.channels.cache.get(newState.channelId!) as VoiceChannel; - // Check if the user has the verifiers role - if (newState.member?.roles.cache.has(IDs.roles.staff.verifier) - || newState.member?.roles.cache.has(IDs.roles.staff.trialVerifier)) { + if (member.roles.cache.has(IDs.roles.staff.verifier) + || member.roles.cache.has(IDs.roles.staff.trialVerifier)) { await channel.setName('Verifier Meeting'); verifier = true; } else { - await channel.setName(`${newState.member?.displayName} - Verification`); - await currentChannel.send(`Hiya ${newState.member?.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); + await channel.setName(`${member.displayName} - Verification`); + await currentChannel.send(`Hiya ${member.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); // Adds to the database that the user joined verification - await joinVerification(newState.member!, channel.id); + await joinVerification(member, channel.id); } // Check how many voice channels there are - const category = guild.channels.cache.get(IDs.categories.verification) as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); // Create a text channel for verifiers only // Checks if there are more than 10 voice channels if (!verifier) { - const verificationText = await guild.channels.create(`✅┃${newState.member?.displayName}-verification`, { + const verificationText = await guild.channels.create(`✅┃${member.displayName}-verification`, { type: 'GUILD_TEXT', - topic: `Channel for verifiers only. ${newState.member?.id} (Please do not change this)`, - parent: IDs.categories.verification, + topic: `Channel for verifiers only. ${member.id} (Please do not change this)`, + parent: category.id, userLimit: 1, permissionOverwrites: [ { @@ -115,7 +130,7 @@ export default class VerificationJoinVCListener extends Listener { }); // Send a message that someone wants to be verified - await verificationText.send(`${newState.member?.user} wants to be verified in ${newState.channel} + await verificationText.send(`${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); } @@ -125,7 +140,7 @@ export default class VerificationJoinVCListener extends Listener { if (listVoiceChannels.size > maxVCs - 1) { await guild.channels.create('Verification', { type: 'GUILD_VOICE', - parent: IDs.categories.verification, + parent: category.id, userLimit: 1, permissionOverwrites: [ { @@ -150,7 +165,7 @@ export default class VerificationJoinVCListener extends Listener { } else { await guild.channels.create('Verification', { type: 'GUILD_VOICE', - parent: IDs.categories.verification, + parent: category.id, userLimit: 1, permissionOverwrites: [ { @@ -184,7 +199,7 @@ export default class VerificationJoinVCListener extends Listener { deny: ['VIEW_CHANNEL'], }, { - id: newState.member!.id, + id: member.id, allow: ['VIEW_CHANNEL'], }, ]); diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 8a12996..dd62aa9 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -34,24 +34,41 @@ export class VerificationLeaveVCListener extends Listener { } public async run(oldState: VoiceState, newState: VoiceState) { + let verifier = false; + + // Check for undefined variables + const { client } = container; + const { channel } = oldState; + const guild = client.guilds.cache.get(newState.guild.id); + + if (channel === null || guild === undefined) { + console.error('Verification channel not found'); + return; + } + + // Get the category + const categoryGuild = guild.channels.cache.get(IDs.categories.verification); + if (categoryGuild === null) { + console.error('Verification channel not found'); + return; + } + const category = categoryGuild as CategoryChannel; + + // Get the user that was being verified + const userSnowflake = await getUser(channel.id); + if (userSnowflake === null) { + verifier = true; + } + // If the event was not a user joining the channel - if (oldState.channel?.parent?.id !== IDs.categories.verification + if (channel.parent?.id !== IDs.categories.verification || newState.channel?.parent?.id === IDs.categories.verification - || oldState.channel.members.size > 0 + || channel.members.size > 0 ) { return; } // Allow more people to join VC if there are less than 10 VCs - const { client } = container; - const guild = client.guilds.cache.get(newState.guild.id)!; - let verifier = false; - - // Get the user that was being verified - const userSnowflake = await getUser(oldState.channel.id); - if (userSnowflake === null) { - verifier = true; - } if (!verifier) { console.log(userSnowflake); @@ -72,13 +89,12 @@ export class VerificationLeaveVCListener extends Listener { } // Check how many voice channels there are - const category = guild.channels.cache.get(IDs.categories.verification) as CategoryChannel; const listVoiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); // Check that it is not deleting the 'Verification' channel (in case bot crashes) - if (oldState.channel.name !== 'Verification') { + if (channel.name !== 'Verification') { // Delete the channel - await oldState.channel!.delete(); + await channel.delete(); } // Delete text channel From 092dcce2fe9a0b6c8de75426aa4d7ad6423b4422 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 18 Aug 2022 05:47:30 +0100 Subject: [PATCH 13/57] feat(arabot): add beginning of verification walkthrough --- src/listeners/verification/joinVC.ts | 146 ++++++++++++++++++++++++-- src/listeners/verification/leaveVC.ts | 16 +-- 2 files changed, 146 insertions(+), 16 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 1d24df7..c4051d5 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -18,7 +18,20 @@ */ import { container, Listener } from '@sapphire/framework'; -import type { VoiceChannel, CategoryChannel, VoiceState } from 'discord.js'; +import type { + VoiceChannel, + CategoryChannel, + VoiceState, + TextChannel, + GuildMember, +} from 'discord.js'; +import { + ButtonInteraction, + Constants, + MessageActionRow, + MessageButton, + MessageEmbed, +} from 'discord.js'; import { maxVCs } from '../../utils/verificationConfig'; import { joinVerification, startVerification } from '../../utils/database/verification'; import IDs from '../../utils/ids'; @@ -32,6 +45,13 @@ export default class VerificationJoinVCListener extends Listener { } public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id === IDs.categories.verification + || newState.channel?.parent?.id !== IDs.categories.verification + ) { + return; + } + // Variable if this channel is a Verifiers only VC let verifier = false; @@ -56,13 +76,6 @@ export default class VerificationJoinVCListener extends Listener { const currentChannel = currentChannelGuild as VoiceChannel; const category = categoryGuild as CategoryChannel; - // If the event was not a user joining the channel - if (oldState.channel?.parent?.id === category.id - || channel.parent?.id !== category.id - ) { - return; - } - // Checks if a verifier has joined if (channel.members.size === 2) { await newState.channel!.permissionOverwrites.set([ @@ -132,6 +145,8 @@ export default class VerificationJoinVCListener extends Listener { // Send a message that someone wants to be verified await verificationText.send(`${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); + + await this.verificationProcess(member, verificationText, channel.id); } // Create a new channel for others to join @@ -205,4 +220,119 @@ export default class VerificationJoinVCListener extends Listener { ]); await currentChannel.setUserLimit(0); } + + private async verificationProcess( + user: GuildMember, + channel: TextChannel, + id: string, + ) { + const embedColor = '#0099ff'; + const { displayName } = user; + + // Create an embeds for each page + const initialEmbed = new MessageEmbed() + .setColor(embedColor) + .setTitle(`Do you think ${displayName} is definitely vegan?`); + + const activistEmbed = new MessageEmbed() + .setColor(embedColor) + .setTitle('Offer to ask questions for Activist. Do you think they should get it?'); + + const noActivistEmbed = new MessageEmbed() + .setColor(embedColor) + .setTitle('Do some activism, asking Activist questions. Now which role should they get?'); + + /* + const vegCuriousEmbed = new MessageEmbed() + .setColor(embedColor) + .setTitle('Should this user get Veg Curious?'); + */ + + // Create buttons to delete or cancel the deletion + const initialButtons = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`yesVegan${id}`) + .setLabel('Yes') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId(`noVegan${id}`) + .setLabel('No') + .setStyle(Constants.MessageButtonStyles.DANGER), + ); + + const activistButtons = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`yesActivist${id}`) + .setLabel('Yes') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId(`noActivist${id}`) + .setLabel('No') + .setStyle(Constants.MessageButtonStyles.DANGER), + ); + + const noActivistButtons = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`vegan${id}`) + .setLabel('Vegan') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId(`convinced${id}`) + .setLabel('Convinced') + .setStyle(Constants.MessageButtonStyles.SECONDARY), + new MessageButton() + .setCustomId(`notVegan${id}`) + .setLabel('Non-vegan') + .setStyle(Constants.MessageButtonStyles.DANGER), + ); + + /* + const vegCuriousButtons = new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId(`yesVegCurious${id}`) + .setLabel('Yes') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId(`noVegCurious${id}`) + .setLabel('No') + .setStyle(Constants.MessageButtonStyles.DANGER), + ); + */ + + // Sends the note to verify this note is to be deleted + const message = await channel.send({ + embeds: [initialEmbed], + components: [initialButtons], + }); + + // Listen for the button presses + const collector = channel.createMessageComponentCollector({ + max: 2, // Maximum of 1 button press + }); + + // Button pressed + collector.on('collect', async (button: ButtonInteraction) => { + // Select roles + // Definitely vegan? + if (button.customId === `yesVegan${id}`) { + await button.deferUpdate(); + await message.edit({ + embeds: [activistEmbed], + components: [activistButtons], + }); + } + // Not as vegan + if (button.customId === `noVegan${id}`) { + await button.deferUpdate(); + await message.edit({ + embeds: [noActivistEmbed], + components: [noActivistButtons], + }); + } + }); + } } diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index dd62aa9..7c67514 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -34,6 +34,14 @@ export class VerificationLeaveVCListener extends Listener { } public async run(oldState: VoiceState, newState: VoiceState) { + // If the event was not a user joining the channel + if (oldState.channel?.parent?.id !== IDs.categories.verification + || newState.channel?.parent?.id === IDs.categories.verification + || oldState.channel.members.size > 0 + ) { + return; + } + let verifier = false; // Check for undefined variables @@ -60,14 +68,6 @@ export class VerificationLeaveVCListener extends Listener { verifier = true; } - // If the event was not a user joining the channel - if (channel.parent?.id !== IDs.categories.verification - || newState.channel?.parent?.id === IDs.categories.verification - || channel.members.size > 0 - ) { - return; - } - // Allow more people to join VC if there are less than 10 VCs if (!verifier) { From ba638bb6e2e7a68e7da93f9dfa26648d7aae5b93 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 19 Aug 2022 03:36:40 +0100 Subject: [PATCH 14/57] feat(arabot): add new scheduler plugin --- docker-compose.yml | 15 +- package-lock.json | 703 +++++++++++++++--- package.json | 6 +- src/index.ts | 15 +- src/{schedules => scheduled-tasks}/standup.ts | 24 +- 5 files changed, 638 insertions(+), 125 deletions(-) rename src/{schedules => scheduled-tasks}/standup.ts (61%) diff --git a/docker-compose.yml b/docker-compose.yml index 7c37a3d..1e36c61 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,23 +3,32 @@ services: image: postgres:14 container_name: postgres restart: always - ports: - - 5432:5432 env_file: - .env volumes: - postgres:/var/lib/postgresql/data + redis: + image: redis:7 + container_name: redis + restart: always + env_file: + - .env + volumes: + - redis:/data + node: build: context: . dockerfile: Dockerfile depends_on: - postgres - restart: on-failure + - redis env_file: - .env volumes: postgres: name: arabot-db + redis: + name: arabot-redis diff --git a/package-lock.json b/package-lock.json index 1e5eea2..fc577ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,15 @@ "license": "GPL-3.0-or-later", "dependencies": { "@prisma/client": "^4.0.0", - "@sapphire/framework": "^3.0.0-next.8007303.0", + "@sapphire/framework": "^3.0.0-next.7dd13af.0", + "@sapphire/plugin-scheduled-tasks": "^4.0.0-next.15d7f9b.0", "@sapphire/plugin-subcommands": "^2.2.2", + "@sapphire/stopwatch": "^1.4.1", "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.7.0", "@types/cron": "^2.0.0", "@types/node": "^18.0.3", + "bullmq": "^1.87.2", "cron": "^2.1.0", "discord-api-types": "^0.33.3", "discord.js": "^13.9.2", @@ -25,6 +28,7 @@ "typescript": "^4.7.4" }, "devDependencies": { + "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", "eslint": "^8.20.0", @@ -145,6 +149,78 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz", + "integrity": "sha512-TyVLn3S/+ikMDsh0gbKv2YydKClN8HaJDDpONlaZR+LVJmsxLFUgA+O7zu59h9+f9gX1aj/ahw9wqa6rosmrYQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.1.2.tgz", + "integrity": "sha512-YPXtcVkhmVNoMGlqp81ZHW4dMxK09msWgnxtsDpSiZwTzUBG2N+No2bsr7WMtBKCVJMSD6mbAl7YhKUqkp/Few==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.1.2.tgz", + "integrity": "sha512-42R4MAFeIeNn+L98qwxAt360bwzX2Kf0ZQkBBucJ2Ircza3asoY4CDbgiu9VWklq8gWJVSJSJBwDI+c/THiWkA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.1.2.tgz", + "integrity": "sha512-vHZ2JiOWF2+DN9lzltGbhtQNzDo8fKFGrf37UJrgqxU0yvtERrzUugnfnX1wmVfFhSsF8OxrfqiNOUc5hko1Zg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.1.2.tgz", + "integrity": "sha512-RjRoRxg7Q3kPAdUSC5EUUPlwfMkIVhmaRTIe+cqHbKrGZ4M6TyCA/b5qMaukQ/1CHWrqYY2FbKOAU8Hg0pQFzg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.1.2.tgz", + "integrity": "sha512-rIZVR48zA8hGkHIK7ED6+ZiXsjRCcAVBJbm8o89OKAMTmEAQ2QvoOxoiu3w2isAaWwzgtQIOFIqHwvZDyLKCvw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -230,13 +306,13 @@ } }, "node_modules/@sapphire/discord.js-utilities": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-4.11.3.tgz", - "integrity": "sha512-ZDQ3Bcw0gemMWmLwUk/dJm/LCPgLyYzJoP3muBJDkZXsyOpmTdJDYh98qxXGaxZ+bAFaqwc2HPWuiTZQNjmEsQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-4.12.0.tgz", + "integrity": "sha512-pBNYyBJNRRMgQ2xD+uljrVZaYJ6TywGUirwBecms8sdbRszm6kDczI3fuEl5tWwgU8vLweAViNZbbYBnts7y2A==", "dependencies": { - "@sapphire/discord-utilities": "^2.11.2", - "@sapphire/time-utilities": "^1.7.4", - "@sapphire/utilities": "^3.6.2", + "@sapphire/discord-utilities": "^2.11.5", + "@sapphire/time-utilities": "^1.7.5", + "@sapphire/utilities": "^3.9.0", "tslib": "^2.4.0" }, "engines": { @@ -245,20 +321,20 @@ } }, "node_modules/@sapphire/framework": { - "version": "3.0.0-next.8007303.0", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0-next.8007303.0.tgz", - "integrity": "sha512-rZWBGWziQeyHli0lF+nXxx5upScBjEDaJu848C6Ef/OnNGaQZobTLzBOdfxOHHJnw1BMeR7Z19wFpq9VTXoz5A==", + "version": "3.0.0-next.7dd13af.0", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0-next.7dd13af.0.tgz", + "integrity": "sha512-WhwRWouTfwLXTAu0xdmZQHN+jcLBkG6mRZc3/I0YRpRSe02pUwEopqSwZgka+TWRfCz3h5DOn+QiFZV4zMlYIw==", "dependencies": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.5", - "@sapphire/discord.js-utilities": "^4.11.3", - "@sapphire/pieces": "^3.3.5", + "@sapphire/discord.js-utilities": "^4.12.0", + "@sapphire/lexure": "^1.0.1", + "@sapphire/pieces": "^3.5.0", "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^1.1.1", + "@sapphire/result": "^2.3.3", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.8.0", + "@sapphire/utilities": "^3.9.0", "@types/object-hash": "^2.2.1", - "lexure": "^0.17.0", "object-hash": "^3.0.0", "tslib": "^2.4.0" }, @@ -267,13 +343,25 @@ "npm": ">=7.0.0" } }, - "node_modules/@sapphire/pieces": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.3.5.tgz", - "integrity": "sha512-Tvoa6kKqNp2ao9P7N8OEPLMB2qP76h5+eug6eADWiZsBkitTlyG2cQRFV2adcuN165bAk+4BJF9dwpYKMhDdfw==", + "node_modules/@sapphire/lexure": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.1.tgz", + "integrity": "sha512-bxI85SqPERicAC8fyZNRjrK2SroXFtpa/vgUNExH8VSM1LIysZE6zDRGCvllAfOdEVGSGBKjNRLfT9kYwNDhXg==", "dependencies": { - "@discordjs/collection": "^1.0.0", - "@sapphire/utilities": "^3.7.0", + "@sapphire/result": "^2.1.1" + }, + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@sapphire/pieces": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.0.tgz", + "integrity": "sha512-4v/gvByVFLX/5M0xCzzpeQLfbO2Q6YbWYVcqEicFWsIlvcW5i50HuNzFnufqgip9w5lSgKGtDSC1xcxvCoZ3WA==", + "dependencies": { + "@discordjs/collection": "^1.0.1", + "@sapphire/utilities": "^3.9.0", "tslib": "^2.4.0" }, "engines": { @@ -281,6 +369,19 @@ "npm": ">=7.0.0" } }, + "node_modules/@sapphire/plugin-scheduled-tasks": { + "version": "4.0.0-next.15d7f9b.0", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0-next.15d7f9b.0.tgz", + "integrity": "sha512-x8NodIFItdZ8LTk+A31pvTrVOWX/fRcAmNbffGoTO6d018iYdfkAa8P6htyIRkARf09pz6BlTesrkL5rGxpImQ==", + "dependencies": { + "@sapphire/time-utilities": "^1.7.5", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=v14.18.0", + "npm": ">=7.24.1" + } + }, "node_modules/@sapphire/plugin-subcommands": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-2.2.2.tgz", @@ -306,9 +407,9 @@ } }, "node_modules/@sapphire/result": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-1.1.1.tgz", - "integrity": "sha512-mKWq+HCu9t+gqVcXMhfH72Trj6cO0LZilpdVYndqRb3+30mrRqs+NtdSf1wAERYEtBmOf3ZWvROe4RPSx7aKvw==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.3.3.tgz", + "integrity": "sha512-q4rBqmgo5B2YGJ4bLl+s/eCHCHACRLFdnKFLg2h56axL7v8RAvuC2p5mlF9RPOTLHodRVpxdK7IUaxCK75zTKA==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -365,9 +466,9 @@ } }, "node_modules/@sapphire/utilities": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.8.0.tgz", - "integrity": "sha512-y33Uuk11z07qjUCuDOHihFF/dF1pq4YfSrgNNRQk6Y0yy5buxfoA8OPTGr4YTIdGq9359ncfIty+HT9htMbygQ==", + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.1.tgz", + "integrity": "sha512-EGXyrpHKQvrmrhgm7ZWMoc2ojpf1D7tb1AcqSjS3n4jKtsRNktuDxOShwXRco5ZMR9yxBCXRgHpuFOZlCn7CLA==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -402,6 +503,15 @@ "@types/node": "*" } }, + "node_modules/@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -776,14 +886,12 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -801,6 +909,27 @@ "node": ">=8" } }, + "node_modules/bullmq": { + "version": "1.87.2", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.87.2.tgz", + "integrity": "sha512-wKZbLYUHkNyQKKA5qr4WwCbUpWYKzy59lXZJe2zVIV7RV4kSLCT9VOJGtGUzRLsO+X3PEMGhxWA4UL0CO+Hz8A==", + "dependencies": { + "cron-parser": "^4.2.1", + "get-port": "^5.1.1", + "glob": "^7.2.0", + "ioredis": "^4.28.5", + "lodash": "^4.17.21", + "msgpackr": "^1.4.6", + "semver": "^7.3.7", + "tslib": "^1.14.1", + "uuid": "^8.3.2" + } + }, + "node_modules/bullmq/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -839,6 +968,14 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -871,8 +1008,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/confusing-browser-globals": { "version": "1.0.11", @@ -893,6 +1029,25 @@ "luxon": "^1.23.x" } }, + "node_modules/cron-parser": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.6.0.tgz", + "integrity": "sha512-guZNLMGUgg6z4+eGhmHGw7ft+v6OQeuHzd1gcLxCo9Yg/qoxmG3nindp2/uwGCLizEisf2H0ptqeVXeoCpP6FA==", + "dependencies": { + "luxon": "^3.0.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/cron-parser/node_modules/luxon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz", + "integrity": "sha512-hF3kv0e5gwHQZKz4wtm4c+inDtyc7elkanAsBq+fundaCdUBNJB1dHEGUZIM6SfSBUlbVFduPwEtNjFK8wLtcw==", + "engines": { + "node": ">=12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -911,7 +1066,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -954,6 +1108,14 @@ "node": ">=0.4.0" } }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "engines": { + "node": ">=0.10" + } + }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -1632,8 +1794,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/function-bind": { "version": "1.1.1", @@ -1688,6 +1849,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -1708,7 +1880,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1884,7 +2055,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -1893,8 +2063,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/internal-slot": { "version": "1.0.3", @@ -1910,6 +2079,31 @@ "node": ">= 0.4" } }, + "node_modules/ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, "node_modules/is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -2159,14 +2353,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lexure": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/lexure/-/lexure-0.17.0.tgz", - "integrity": "sha512-0L8GqFgPW36sLNqxdp2VOOef5Ajpb98kc0Zk4AzE+Yf0xYTDndcT1vpFqwkTdrCCw+FV8DH4mC9NUw0RlARThA==", - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -2182,6 +2368,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2197,7 +2403,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -2263,7 +2468,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2280,8 +2484,36 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/msgpackr": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", + "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "optionalDependencies": { + "msgpackr-extract": "^2.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz", + "integrity": "sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.0.3" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "2.1.2" + } }, "node_modules/natural-compare": { "version": "1.4.0", @@ -2308,6 +2540,17 @@ } } }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", + "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, "node_modules/object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -2387,7 +2630,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -2439,6 +2681,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "engines": { + "node": ">=6" + } + }, "node_modules/p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -2473,7 +2723,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2568,6 +2817,30 @@ } ] }, + "node_modules/redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -2675,7 +2948,6 @@ "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -2730,6 +3002,11 @@ "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -2983,6 +3260,14 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -3051,8 +3336,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { "version": "8.8.1", @@ -3077,8 +3361,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yn": { "version": "3.1.1", @@ -3193,6 +3476,42 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz", + "integrity": "sha512-TyVLn3S/+ikMDsh0gbKv2YydKClN8HaJDDpONlaZR+LVJmsxLFUgA+O7zu59h9+f9gX1aj/ahw9wqa6rosmrYQ==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.1.2.tgz", + "integrity": "sha512-YPXtcVkhmVNoMGlqp81ZHW4dMxK09msWgnxtsDpSiZwTzUBG2N+No2bsr7WMtBKCVJMSD6mbAl7YhKUqkp/Few==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.1.2.tgz", + "integrity": "sha512-42R4MAFeIeNn+L98qwxAt360bwzX2Kf0ZQkBBucJ2Ircza3asoY4CDbgiu9VWklq8gWJVSJSJBwDI+c/THiWkA==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.1.2.tgz", + "integrity": "sha512-vHZ2JiOWF2+DN9lzltGbhtQNzDo8fKFGrf37UJrgqxU0yvtERrzUugnfnX1wmVfFhSsF8OxrfqiNOUc5hko1Zg==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.1.2.tgz", + "integrity": "sha512-RjRoRxg7Q3kPAdUSC5EUUPlwfMkIVhmaRTIe+cqHbKrGZ4M6TyCA/b5qMaukQ/1CHWrqYY2FbKOAU8Hg0pQFzg==", + "optional": true + }, + "@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.1.2.tgz", + "integrity": "sha512-rIZVR48zA8hGkHIK7ED6+ZiXsjRCcAVBJbm8o89OKAMTmEAQ2QvoOxoiu3w2isAaWwzgtQIOFIqHwvZDyLKCvw==", + "optional": true + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3248,42 +3567,59 @@ "integrity": "sha512-j71swcPmRKyIEPnw1jP92lW81IUAAemQgWqaEKuRVdW3C3F3XfUVviv7T88+CnfbVY8zHsoYxAZEMM12Sw8QcQ==" }, "@sapphire/discord.js-utilities": { - "version": "4.11.3", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-4.11.3.tgz", - "integrity": "sha512-ZDQ3Bcw0gemMWmLwUk/dJm/LCPgLyYzJoP3muBJDkZXsyOpmTdJDYh98qxXGaxZ+bAFaqwc2HPWuiTZQNjmEsQ==", + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-4.12.0.tgz", + "integrity": "sha512-pBNYyBJNRRMgQ2xD+uljrVZaYJ6TywGUirwBecms8sdbRszm6kDczI3fuEl5tWwgU8vLweAViNZbbYBnts7y2A==", "requires": { - "@sapphire/discord-utilities": "^2.11.2", - "@sapphire/time-utilities": "^1.7.4", - "@sapphire/utilities": "^3.6.2", + "@sapphire/discord-utilities": "^2.11.5", + "@sapphire/time-utilities": "^1.7.5", + "@sapphire/utilities": "^3.9.0", "tslib": "^2.4.0" } }, "@sapphire/framework": { - "version": "3.0.0-next.8007303.0", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0-next.8007303.0.tgz", - "integrity": "sha512-rZWBGWziQeyHli0lF+nXxx5upScBjEDaJu848C6Ef/OnNGaQZobTLzBOdfxOHHJnw1BMeR7Z19wFpq9VTXoz5A==", + "version": "3.0.0-next.7dd13af.0", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0-next.7dd13af.0.tgz", + "integrity": "sha512-WhwRWouTfwLXTAu0xdmZQHN+jcLBkG6mRZc3/I0YRpRSe02pUwEopqSwZgka+TWRfCz3h5DOn+QiFZV4zMlYIw==", "requires": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.5", - "@sapphire/discord.js-utilities": "^4.11.3", - "@sapphire/pieces": "^3.3.5", + "@sapphire/discord.js-utilities": "^4.12.0", + "@sapphire/lexure": "^1.0.1", + "@sapphire/pieces": "^3.5.0", "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^1.1.1", + "@sapphire/result": "^2.3.3", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.8.0", + "@sapphire/utilities": "^3.9.0", "@types/object-hash": "^2.2.1", - "lexure": "^0.17.0", "object-hash": "^3.0.0", "tslib": "^2.4.0" } }, - "@sapphire/pieces": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.3.5.tgz", - "integrity": "sha512-Tvoa6kKqNp2ao9P7N8OEPLMB2qP76h5+eug6eADWiZsBkitTlyG2cQRFV2adcuN165bAk+4BJF9dwpYKMhDdfw==", + "@sapphire/lexure": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.1.tgz", + "integrity": "sha512-bxI85SqPERicAC8fyZNRjrK2SroXFtpa/vgUNExH8VSM1LIysZE6zDRGCvllAfOdEVGSGBKjNRLfT9kYwNDhXg==", "requires": { - "@discordjs/collection": "^1.0.0", - "@sapphire/utilities": "^3.7.0", + "@sapphire/result": "^2.1.1" + } + }, + "@sapphire/pieces": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.0.tgz", + "integrity": "sha512-4v/gvByVFLX/5M0xCzzpeQLfbO2Q6YbWYVcqEicFWsIlvcW5i50HuNzFnufqgip9w5lSgKGtDSC1xcxvCoZ3WA==", + "requires": { + "@discordjs/collection": "^1.0.1", + "@sapphire/utilities": "^3.9.0", + "tslib": "^2.4.0" + } + }, + "@sapphire/plugin-scheduled-tasks": { + "version": "4.0.0-next.15d7f9b.0", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0-next.15d7f9b.0.tgz", + "integrity": "sha512-x8NodIFItdZ8LTk+A31pvTrVOWX/fRcAmNbffGoTO6d018iYdfkAa8P6htyIRkARf09pz6BlTesrkL5rGxpImQ==", + "requires": { + "@sapphire/time-utilities": "^1.7.5", "tslib": "^2.4.0" } }, @@ -3304,9 +3640,9 @@ } }, "@sapphire/result": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-1.1.1.tgz", - "integrity": "sha512-mKWq+HCu9t+gqVcXMhfH72Trj6cO0LZilpdVYndqRb3+30mrRqs+NtdSf1wAERYEtBmOf3ZWvROe4RPSx7aKvw==" + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.3.3.tgz", + "integrity": "sha512-q4rBqmgo5B2YGJ4bLl+s/eCHCHACRLFdnKFLg2h56axL7v8RAvuC2p5mlF9RPOTLHodRVpxdK7IUaxCK75zTKA==" }, "@sapphire/shapeshift": { "version": "3.5.1", @@ -3343,9 +3679,9 @@ } }, "@sapphire/utilities": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.8.0.tgz", - "integrity": "sha512-y33Uuk11z07qjUCuDOHihFF/dF1pq4YfSrgNNRQk6Y0yy5buxfoA8OPTGr4YTIdGq9359ncfIty+HT9htMbygQ==" + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.1.tgz", + "integrity": "sha512-EGXyrpHKQvrmrhgm7ZWMoc2ojpf1D7tb1AcqSjS3n4jKtsRNktuDxOShwXRco5ZMR9yxBCXRgHpuFOZlCn7CLA==" }, "@tsconfig/node10": { "version": "1.0.9", @@ -3376,6 +3712,15 @@ "@types/node": "*" } }, + "@types/ioredis": { + "version": "4.28.10", + "resolved": "https://registry.npmjs.org/@types/ioredis/-/ioredis-4.28.10.tgz", + "integrity": "sha512-69LyhUgrXdgcNDv7ogs1qXZomnfOEnSmrmMFqKgt1XMJxmoOSG/u3wYy13yACIfKuMJ8IhKgHafDO3sx19zVQQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -3621,14 +3966,12 @@ "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3643,6 +3986,29 @@ "fill-range": "^7.0.1" } }, + "bullmq": { + "version": "1.87.2", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.87.2.tgz", + "integrity": "sha512-wKZbLYUHkNyQKKA5qr4WwCbUpWYKzy59lXZJe2zVIV7RV4kSLCT9VOJGtGUzRLsO+X3PEMGhxWA4UL0CO+Hz8A==", + "requires": { + "cron-parser": "^4.2.1", + "get-port": "^5.1.1", + "glob": "^7.2.0", + "ioredis": "^4.28.5", + "lodash": "^4.17.21", + "msgpackr": "^1.4.6", + "semver": "^7.3.7", + "tslib": "^1.14.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3669,6 +4035,11 @@ "supports-color": "^7.1.0" } }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3695,8 +4066,7 @@ "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "confusing-browser-globals": { "version": "1.0.11", @@ -3717,6 +4087,21 @@ "luxon": "^1.23.x" } }, + "cron-parser": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-4.6.0.tgz", + "integrity": "sha512-guZNLMGUgg6z4+eGhmHGw7ft+v6OQeuHzd1gcLxCo9Yg/qoxmG3nindp2/uwGCLizEisf2H0ptqeVXeoCpP6FA==", + "requires": { + "luxon": "^3.0.1" + }, + "dependencies": { + "luxon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz", + "integrity": "sha512-hF3kv0e5gwHQZKz4wtm4c+inDtyc7elkanAsBq+fundaCdUBNJB1dHEGUZIM6SfSBUlbVFduPwEtNjFK8wLtcw==" + } + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3732,7 +4117,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -3758,6 +4142,11 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, + "denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -4294,8 +4683,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "function-bind": { "version": "1.1.1", @@ -4338,6 +4726,11 @@ "has-symbols": "^1.0.3" } }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-symbol-description": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", @@ -4352,7 +4745,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4471,7 +4863,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -4480,8 +4871,7 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "internal-slot": { "version": "1.0.3", @@ -4494,6 +4884,24 @@ "side-channel": "^1.0.4" } }, + "ioredis": { + "version": "4.28.5", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz", + "integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "lodash.isarguments": "^3.1.0", + "p-map": "^2.1.0", + "redis-commands": "1.7.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + } + }, "is-bigint": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", @@ -4665,11 +5073,6 @@ "type-check": "~0.4.0" } }, - "lexure": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/lexure/-/lexure-0.17.0.tgz", - "integrity": "sha512-0L8GqFgPW36sLNqxdp2VOOef5Ajpb98kc0Zk4AzE+Yf0xYTDndcT1vpFqwkTdrCCw+FV8DH4mC9NUw0RlARThA==" - }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4679,6 +5082,26 @@ "p-locate": "^5.0.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==" + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4694,7 +5117,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -4742,7 +5164,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4756,8 +5177,30 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "msgpackr": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", + "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "requires": { + "msgpackr-extract": "^2.0.2" + } + }, + "msgpackr-extract": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.1.2.tgz", + "integrity": "sha512-cmrmERQFb19NX2JABOGtrKdHMyI6RUyceaPBQ2iRz9GnDkjBWFjNJC0jyyoOfZl2U/LZE3tQCCQc4dlRyA8mcA==", + "optional": true, + "requires": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "2.1.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "2.1.2", + "node-gyp-build-optional-packages": "5.0.3" + } }, "natural-compare": { "version": "1.4.0", @@ -4773,6 +5216,12 @@ "whatwg-url": "^5.0.0" } }, + "node-gyp-build-optional-packages": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", + "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "optional": true + }, "object-hash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", @@ -4828,7 +5277,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "requires": { "wrappy": "1" } @@ -4865,6 +5313,11 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==" + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -4889,8 +5342,7 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, "path-key": { "version": "3.1.1", @@ -4942,6 +5394,24 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, + "redis-commands": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz", + "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ==" + }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "requires": { + "redis-errors": "^1.0.0" + } + }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -5004,7 +5474,6 @@ "version": "7.3.7", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, "requires": { "lru-cache": "^6.0.0" } @@ -5041,6 +5510,11 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "string.prototype.trimend": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", @@ -5219,6 +5693,11 @@ "punycode": "^2.1.0" } }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -5275,8 +5754,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { "version": "8.8.1", @@ -5287,8 +5765,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yn": { "version": "3.1.1", diff --git a/package.json b/package.json index c9103dc..4c071c4 100644 --- a/package.json +++ b/package.json @@ -27,12 +27,15 @@ "homepage": "https://github.com/veganhacktivists/arabot#readme", "dependencies": { "@prisma/client": "^4.0.0", - "@sapphire/framework": "^3.0.0-next.8007303.0", + "@sapphire/framework": "^3.0.0-next.7dd13af.0", + "@sapphire/plugin-scheduled-tasks": "^4.0.0-next.15d7f9b.0", "@sapphire/plugin-subcommands": "^2.2.2", + "@sapphire/stopwatch": "^1.4.1", "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.7.0", "@types/cron": "^2.0.0", "@types/node": "^18.0.3", + "bullmq": "^1.87.2", "cron": "^2.1.0", "discord-api-types": "^0.33.3", "discord.js": "^13.9.2", @@ -42,6 +45,7 @@ "typescript": "^4.7.4" }, "devDependencies": { + "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", "eslint": "^8.20.0", diff --git a/src/index.ts b/src/index.ts index 8a78866..7459d21 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,7 +21,7 @@ */ import { LogLevel, SapphireClient } from '@sapphire/framework'; -import { ScheduleManager } from './utils/scheduleManager'; +import { ScheduledTaskRedisStrategy } from '@sapphire/plugin-scheduled-tasks/register-redis'; require('dotenv').config(); @@ -43,6 +43,16 @@ const client = new SapphireClient({ 'DIRECT_MESSAGES', 'DIRECT_MESSAGE_REACTIONS', ], + tasks: { + // Scheduler with redis + strategy: new ScheduledTaskRedisStrategy({ + bull: { + connection: { + host: 'redis', + }, + }, + }), + }, }); // Main function to log in @@ -57,9 +67,6 @@ const main = async () => { client.destroy(); process.exit(1); } - - // Scheduled Commands - await ScheduleManager(); }; main(); diff --git a/src/schedules/standup.ts b/src/scheduled-tasks/standup.ts similarity index 61% rename from src/schedules/standup.ts rename to src/scheduled-tasks/standup.ts index 1b64d68..9aef1bf 100644 --- a/src/schedules/standup.ts +++ b/src/scheduled-tasks/standup.ts @@ -17,15 +17,31 @@ along with this program. If not, see . */ +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; import { container } from '@sapphire/framework'; import type { TextChannel } from 'discord.js'; import IDs from '../utils/ids'; -export async function standupRun() { - const { client } = container; +export class StandupTask extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, { + ...options, + cron: '0 12 * * 1', + }); + } - const channel = client.channels.cache.get(IDs.channels.staff.coordinators) as TextChannel; + public async run() { + const { client } = container; - await channel.send(`Hiya <@&${IDs.roles.staff.coordinator}> it's time for your weekly standup! + const channel = client.channels.cache.get(IDs.channels.staff.coordinators) as TextChannel; + + await channel.send(`Hiya <@&${IDs.roles.staff.coordinator}> it's time for your weekly standup! \nPlease submit it in <#${IDs.channels.staff.standup}> :)`); + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + cron: never; + } } From 300ad9a903781c19ad1b1531530b5bbea0bd1474 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 19 Aug 2022 03:51:11 +0100 Subject: [PATCH 15/57] refactor(arabot): move database functions --- src/commands/mod/sus.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/mod/sus.ts b/src/commands/mod/sus.ts index 7c8be59..3a92a99 100644 --- a/src/commands/mod/sus.ts +++ b/src/commands/mod/sus.ts @@ -23,8 +23,8 @@ import { } from 'discord.js'; import { PrismaClient } from '@prisma/client'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; -import { addExistingUser, userExists } from '../../utils/dbExistingUser'; -import { IDs } from '../../utils/ids'; +import { addExistingUser, userExists } from '../../utils/database/dbExistingUser'; +import IDs from '../../utils/ids'; // TODO add a check when they join the server to give the user the sus role again From 4883ec12a10c3655d44cd88edd9d8904714c3454 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 19 Aug 2022 03:51:42 +0100 Subject: [PATCH 16/57] feat(verification): add info to be collected --- prisma/schema.prisma | 19 +++++++++++-------- src/listeners/verification/joinVC.ts | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 11506a2..24daf5f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -48,16 +48,19 @@ model User { } model Verify { - id Int @id @default(autoincrement()) - user User @relation("verUser", fields: [userId], references: [id]) + id String @id + user User @relation("verUser", fields: [userId], references: [id]) userId String - verifier User? @relation("verVerifier", fields: [verifierId], references: [id]) + verifier User? @relation("verVerifier", fields: [verifierId], references: [id]) verifierId String? - time DateTime @default(now()) - timedOut Boolean @default(false) // If they got kicked out of verification because they timed out - vegan Boolean @default(false) // If they got verified as a vegan - text Boolean @default(false) // If they used text verification - serverVegan Boolean @default(false) // People that went vegan on the server + joinTime DateTime @default(now()) + startTime DateTime? + finishTime DateTime? + timedOut Boolean @default(false) // If they got kicked out of verification because they timed out + //incomplete Boolean @default(false) // If the verification was incomplete + vegan Boolean @default(false) // If they got verified as a vegan + text Boolean @default(false) // If they used text verification + serverVegan Boolean @default(false) // People that went vegan on the server notes String? } diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index c4051d5..48997de 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -228,6 +228,24 @@ export default class VerificationJoinVCListener extends Listener { ) { const embedColor = '#0099ff'; const { displayName } = user; + let info = { + page: 0, + find: { + reason: 0, + where: 0, + }, + length: 0, + reasoning: 0, + life: 0, + food: 0, + roles: { + vegan: false, + activist: false, + trusted: false, + vegCurious: false, + convinced: false, + }, + }; // Create an embeds for each page const initialEmbed = new MessageEmbed() @@ -320,6 +338,7 @@ export default class VerificationJoinVCListener extends Listener { // Definitely vegan? if (button.customId === `yesVegan${id}`) { await button.deferUpdate(); + info.roles.vegan = true; await message.edit({ embeds: [activistEmbed], components: [activistButtons], From b2d11b662751fe1a7a344bb8bf600932040bb65b Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 19 Aug 2022 03:52:30 +0100 Subject: [PATCH 17/57] feat(arabot): remove old schedule manager --- src/utils/scheduleManager.ts | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 src/utils/scheduleManager.ts diff --git a/src/utils/scheduleManager.ts b/src/utils/scheduleManager.ts deleted file mode 100644 index 25d6d7c..0000000 --- a/src/utils/scheduleManager.ts +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - Animal Rights Advocates Discord Bot - Copyright (C) 2022 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 . - */ - -import { CronJob } from 'cron'; -import { standupRun } from '../schedules/standup'; - -export async function ScheduleManager() { - // TODO add a way to automatically add all schedules in the schedules folder - // Define Jobs: - // Standup - const standup = new CronJob( - '00 00 12 * * 1', - (async () => { - await standupRun(); - }), - ); - - // Start Jobs: - standup.start(); -} From b56755943825e9a7aebe3e1decbb96aeff16c826 Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 22 Aug 2022 22:57:37 +0100 Subject: [PATCH 18/57] feat(config): update dev dependencies and fix tsconfig --- package-lock.json | 4 +++- package.json | 2 +- tsconfig.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index ea749e8..5cc1f51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.9.2", "@types/node": "^18.0.3", "bullmq": "^1.89.1", @@ -26,6 +25,7 @@ "typescript": "^4.7.4" }, "devDependencies": { + "@sapphire/ts-config": "^3.3.4", "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", @@ -460,6 +460,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/@sapphire/ts-config/-/ts-config-3.3.4.tgz", "integrity": "sha512-mWEUxCXh3cHKI7C8HJ049exVTMNaq+A/lJEDfM5ENSQ/OOZHd5DdmXn2jrYqFWbTRCHa0Vp2FAmACWBwePsBtg==", + "dev": true, "dependencies": { "tslib": "^2.3.1", "typescript": "^4.6.3" @@ -3607,6 +3608,7 @@ "version": "3.3.4", "resolved": "https://registry.npmjs.org/@sapphire/ts-config/-/ts-config-3.3.4.tgz", "integrity": "sha512-mWEUxCXh3cHKI7C8HJ049exVTMNaq+A/lJEDfM5ENSQ/OOZHd5DdmXn2jrYqFWbTRCHa0Vp2FAmACWBwePsBtg==", + "dev": true, "requires": { "tslib": "^2.3.1", "typescript": "^4.6.3" diff --git a/package.json b/package.json index 6651cef..f52553c 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", - "@sapphire/ts-config": "^3.3.4", "@sapphire/utilities": "^3.9.2", "@types/node": "^18.0.3", "bullmq": "^1.89.1", @@ -43,6 +42,7 @@ "typescript": "^4.7.4" }, "devDependencies": { + "@sapphire/ts-config": "^3.3.4", "@types/ioredis": "^4.28.10", "@typescript-eslint/eslint-plugin": "^5.30.7", "@typescript-eslint/parser": "^5.30.7", diff --git a/tsconfig.json b/tsconfig.json index e2256ed..59e91d1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -101,7 +101,7 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + // "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, "include": ["src"] } From 2b96d507eb692b8d9256ad58dfa831745272f900 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 23 Aug 2022 02:05:13 +0100 Subject: [PATCH 19/57] fix(verification): fix multiple eslint issues --- .eslintrc.json | 1 + package-lock.json | 19 ++-- package.json | 3 +- src/commands/fun/1984.ts | 4 +- src/commands/fun/happy.ts | 4 +- src/commands/fun/hug.ts | 5 +- src/commands/fun/kill.ts | 5 +- src/commands/fun/poke.ts | 4 +- src/commands/fun/sad.ts | 4 +- src/commands/fun/shrug.ts | 4 +- src/commands/mod/diversityToggleOpen.ts | 22 +++-- src/commands/mod/sus.ts | 49 ++++++----- src/commands/roles/stagehost.ts | 4 +- src/commands/roles/vegcurious.ts | 4 +- src/commands/utils/ping.ts | 4 +- src/commands/verification/purgeVerifying.ts | 4 +- src/listeners/deniedPermission.ts | 4 +- src/listeners/ready.ts | 4 +- src/preconditions/CoordinatorOnly.ts | 4 +- src/preconditions/DevCoordinatorOnly.ts | 4 +- src/preconditions/DiversityCoordinatorOnly.ts | 4 +- src/preconditions/EventCoordinatorOnly.ts | 4 +- src/preconditions/MentorCoordinatorOnly.ts | 4 +- src/preconditions/ModOnly.ts | 4 +- src/preconditions/PatreonOnly.ts | 4 +- src/preconditions/VerifierCoordinatorOnly.ts | 4 +- src/preconditions/VerifierOnly.ts | 4 +- src/scheduled-tasks/appleWarning.ts | 50 +++++++++++ src/scheduled-tasks/standup.ts | 4 +- src/utils/dbExistingUser.ts | 87 +++++++++++++++++++ src/utils/devIDs.ts | 6 ++ src/utils/ids.ts | 7 ++ 32 files changed, 273 insertions(+), 65 deletions(-) create mode 100644 src/scheduled-tasks/appleWarning.ts create mode 100644 src/utils/dbExistingUser.ts diff --git a/.eslintrc.json b/.eslintrc.json index 06613cf..0269b34 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,5 +17,6 @@ "@typescript-eslint" ], "rules": { + "class-methods-use-this": "off" } } diff --git a/package-lock.json b/package-lock.json index 5cc1f51..f9d49d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "GPL-3.0-or-later", "dependencies": { "@prisma/client": "^4.0.0", + "@sapphire/discord.js-utilities": "^5.0.0", "@sapphire/framework": "^3.0.0", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", @@ -18,7 +19,7 @@ "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.2", + "discord.js": "^13.10.3", "dotenv": "^16.0.1", "prisma": "^4.2.1", "ts-node": "^10.8.2", @@ -1114,13 +1115,13 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "node_modules/discord.js": { - "version": "13.10.2", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.2.tgz", - "integrity": "sha512-zPhPaUvJRCqmsqMBmQ8gJ8k/O0rcuLj8tn/mOaJEiDPkpb5aFULHarOfqND6jRuLrKXd2to/bc0mjXTOgRW1MA==", + "version": "13.10.3", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", + "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", "dependencies": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", - "@sapphire/async-queue": "^1.3.2", + "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", "discord-api-types": "^0.33.3", @@ -4069,13 +4070,13 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "discord.js": { - "version": "13.10.2", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.2.tgz", - "integrity": "sha512-zPhPaUvJRCqmsqMBmQ8gJ8k/O0rcuLj8tn/mOaJEiDPkpb5aFULHarOfqND6jRuLrKXd2to/bc0mjXTOgRW1MA==", + "version": "13.10.3", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", + "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", "requires": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", - "@sapphire/async-queue": "^1.3.2", + "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", "discord-api-types": "^0.33.3", diff --git a/package.json b/package.json index f52553c..77430ba 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "homepage": "https://github.com/veganhacktivists/arabot#readme", "dependencies": { "@prisma/client": "^4.0.0", + "@sapphire/discord.js-utilities": "^5.0.0", "@sapphire/framework": "^3.0.0", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", @@ -35,7 +36,7 @@ "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.2", + "discord.js": "^13.10.3", "dotenv": "^16.0.1", "prisma": "^4.2.1", "ts-node": "^10.8.2", diff --git a/src/commands/fun/1984.ts b/src/commands/fun/1984.ts index a7f5ee8..d486633 100644 --- a/src/commands/fun/1984.ts +++ b/src/commands/fun/1984.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { N1984 } from '../../utils/gifs'; -export class N1984Command extends Command { +class N1984Command extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -63,3 +63,5 @@ export class N1984Command extends Command { await interaction.reply({ embeds: [n1984Embed], fetchReply: true }); } } + +export default N1984Command; diff --git a/src/commands/fun/happy.ts b/src/commands/fun/happy.ts index 3cde127..7d62023 100644 --- a/src/commands/fun/happy.ts +++ b/src/commands/fun/happy.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Happy } from '../../utils/gifs'; -export class HappyCommand extends Command { +class HappyCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -61,3 +61,5 @@ export class HappyCommand extends Command { await interaction.reply({ embeds: [happyEmbed], fetchReply: true }); } } + +export default HappyCommand; diff --git a/src/commands/fun/hug.ts b/src/commands/fun/hug.ts index 84a0a42..d305450 100644 --- a/src/commands/fun/hug.ts +++ b/src/commands/fun/hug.ts @@ -21,13 +21,12 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Hugs } from '../../utils/gifs'; -export class HugCommand extends Command { +class HugCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, name: 'hug', description: 'Hug a user', - preconditions: [['CoordinatorOnly', 'PatreonOnly']], }); } @@ -65,3 +64,5 @@ export class HugCommand extends Command { await interaction.reply({ content: `<@${user.id}>`, embeds: [hugEmbed], fetchReply: true }); } } + +export default HugCommand; diff --git a/src/commands/fun/kill.ts b/src/commands/fun/kill.ts index a584c23..7c35ab4 100644 --- a/src/commands/fun/kill.ts +++ b/src/commands/fun/kill.ts @@ -21,13 +21,12 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Kill } from '../../utils/gifs'; -export class KillCommand extends Command { +class KillCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, name: 'kill', description: 'Kill a user', - preconditions: [['CoordinatorOnly', 'PatreonOnly']], }); } @@ -65,3 +64,5 @@ export class KillCommand extends Command { await interaction.reply({ content: `<@${user.id}>`, embeds: [killEmbed], fetchReply: true }); } } + +export default KillCommand; diff --git a/src/commands/fun/poke.ts b/src/commands/fun/poke.ts index 5f8af92..3981714 100644 --- a/src/commands/fun/poke.ts +++ b/src/commands/fun/poke.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Poke } from '../../utils/gifs'; -export class PokeCommand extends Command { +class PokeCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -65,3 +65,5 @@ export class PokeCommand extends Command { await interaction.reply({ content: `<@${user.id}>`, embeds: [pokeEmbed], fetchReply: true }); } } + +export default PokeCommand; diff --git a/src/commands/fun/sad.ts b/src/commands/fun/sad.ts index d73183c..a5e8811 100644 --- a/src/commands/fun/sad.ts +++ b/src/commands/fun/sad.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Sad } from '../../utils/gifs'; -export class SadCommand extends Command { +class SadCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -61,3 +61,5 @@ export class SadCommand extends Command { await interaction.reply({ embeds: [sadEmbed], fetchReply: true }); } } + +export default SadCommand; diff --git a/src/commands/fun/shrug.ts b/src/commands/fun/shrug.ts index b4f6c1a..18909d5 100644 --- a/src/commands/fun/shrug.ts +++ b/src/commands/fun/shrug.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed } from 'discord.js'; import { Shrug } from '../../utils/gifs'; -export class ShrugCommand extends Command { +class ShrugCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -61,3 +61,5 @@ export class ShrugCommand extends Command { await interaction.reply({ embeds: [shrugEmbed], fetchReply: true }); } } + +export default ShrugCommand; diff --git a/src/commands/mod/diversityToggleOpen.ts b/src/commands/mod/diversityToggleOpen.ts index c1f564c..bd49301 100644 --- a/src/commands/mod/diversityToggleOpen.ts +++ b/src/commands/mod/diversityToggleOpen.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import type { TextChannel } from 'discord.js'; import IDs from '../../utils/ids'; -export class ToggleOpenCommand extends Command { +class ToggleOpenCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -52,16 +52,18 @@ export class ToggleOpenCommand extends Command { // Checks what subcommand was run switch (subcommand) { case 'toggleopen': { - return await this.toggleOpen(interaction); + await this.toggleOpen(interaction); + return; + } + default: { + // If subcommand is invalid + await interaction.reply({ + content: 'Invalid sub command!', + ephemeral: true, + fetchReply: true, + }); } } - - // If subcommand is invalid - await interaction.reply({ - content: 'Invalid sub command!', - ephemeral: true, - fetchReply: true, - }); } // Command run @@ -123,3 +125,5 @@ export class ToggleOpenCommand extends Command { }); } } + +export default ToggleOpenCommand; diff --git a/src/commands/mod/sus.ts b/src/commands/mod/sus.ts index d91fc70..fb2d9d7 100644 --- a/src/commands/mod/sus.ts +++ b/src/commands/mod/sus.ts @@ -59,7 +59,7 @@ async function findNotes(userId: string, active: boolean) { const prisma = new PrismaClient(); // Query to get the specific user's sus notes - const getNote = await prisma.sus.findMany({ + const note = await prisma.sus.findMany({ where: { userId, active, @@ -68,7 +68,7 @@ async function findNotes(userId: string, active: boolean) { // Close the database connection await prisma.$disconnect(); - return getNote; + return note; } // Get one note from the id @@ -77,7 +77,7 @@ async function getNote(noteId: number) { const prisma = new PrismaClient(); // Query to get the specific user's sus notes - const getNote = await prisma.sus.findUnique({ + const note = await prisma.sus.findUnique({ where: { id: noteId, }, @@ -85,7 +85,7 @@ async function getNote(noteId: number) { // Close the database connection await prisma.$disconnect(); - return getNote; + return note; } async function deactivateNote(noteId: number) { @@ -127,7 +127,7 @@ async function deactivateAllNotes(userId: string) { } // Main command -export class SusCommand extends Command { +class SusCommand extends Command { public constructor(context: Command.Context) { super(context, { name: 'sus', @@ -182,29 +182,34 @@ export class SusCommand extends Command { // Checks what subcommand was run switch (subcommand) { case 'add': { - return await this.addNote(interaction); + await this.addNote(interaction); + return; } case 'view': { - return await this.listNote(interaction); + await this.listNote(interaction); + return; } case 'remove': { - return await this.removeNote(interaction); + await this.removeNote(interaction); + return; } case 'purge': { - return await this.removeAllNotes(interaction); + await this.removeAllNotes(interaction); + return; + } + default: { + // If subcommand is invalid + await interaction.reply({ + content: 'Invalid sub command!', + ephemeral: true, + fetchReply: true, + }); } } - - // If subcommand is invalid - await interaction.reply({ - content: 'Invalid sub command!', - ephemeral: true, - fetchReply: true, - }); } // Subcommand to add sus note - public async addNote(interaction: Command.ChatInputInteraction) { + private async addNote(interaction: Command.ChatInputInteraction) { // Get the arguments let user = interaction.options.getUser('user'); let note = interaction.options.getString('note'); @@ -261,7 +266,7 @@ export class SusCommand extends Command { }); } - public async listNote(interaction: Command.ChatInputInteraction) { + private async listNote(interaction: Command.ChatInputInteraction) { // Get the arguments let user = interaction.options.getUser('user'); const { guild } = interaction; @@ -321,7 +326,7 @@ export class SusCommand extends Command { }); } - public async removeNote(interaction: Command.ChatInputInteraction) { + private async removeNote(interaction: Command.ChatInputInteraction) { // Get the arguments let noteId = interaction.options.getInteger('id'); const { guild, channel } = interaction; @@ -375,7 +380,7 @@ export class SusCommand extends Command { .setThumbnail(user!.avatarURL()!) // TODO avatar does not show when run .addField( `ID: ${noteId} | Moderator: ${modName} | Date: `, - note!.note, + note!.note, ); // Create buttons to delete or cancel the deletion @@ -439,7 +444,7 @@ export class SusCommand extends Command { }); } - public async removeAllNotes(interaction: Command.ChatInputInteraction) { + private async removeAllNotes(interaction: Command.ChatInputInteraction) { // Get the arguments const user = interaction.options.getUser('user'); const { guild, channel } = interaction; @@ -557,3 +562,5 @@ export class SusCommand extends Command { await userGuildMember!.roles.remove(IDs.roles.restrictions.sus); } } + +export default SusCommand; diff --git a/src/commands/roles/stagehost.ts b/src/commands/roles/stagehost.ts index a4da8d8..95e4c8b 100644 --- a/src/commands/roles/stagehost.ts +++ b/src/commands/roles/stagehost.ts @@ -20,7 +20,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import IDs from '../../utils/ids'; -export class StageHostCommand extends Command { +class StageHostCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -98,3 +98,5 @@ export class StageHostCommand extends Command { }); } } + +export default StageHostCommand; diff --git a/src/commands/roles/vegcurious.ts b/src/commands/roles/vegcurious.ts index 7832fe1..44a9d84 100644 --- a/src/commands/roles/vegcurious.ts +++ b/src/commands/roles/vegcurious.ts @@ -20,7 +20,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import IDs from '../../utils/ids'; -export class VegCuriousCommand extends Command { +class VegCuriousCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -109,3 +109,5 @@ export class VegCuriousCommand extends Command { }); } } + +export default VegCuriousCommand; diff --git a/src/commands/utils/ping.ts b/src/commands/utils/ping.ts index 7055331..7a342ae 100644 --- a/src/commands/utils/ping.ts +++ b/src/commands/utils/ping.ts @@ -20,7 +20,7 @@ import { isMessageInstance } from '@sapphire/discord.js-utilities'; import { Command } from '@sapphire/framework'; -export class PingCommand extends Command { +class PingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -49,3 +49,5 @@ export class PingCommand extends Command { return interaction.editReply('Failed to retrieve ping :('); } } + +export default PingCommand; diff --git a/src/commands/verification/purgeVerifying.ts b/src/commands/verification/purgeVerifying.ts index 50c883f..7e0bc10 100644 --- a/src/commands/verification/purgeVerifying.ts +++ b/src/commands/verification/purgeVerifying.ts @@ -21,7 +21,7 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; import IDs from '../../utils/ids'; -export class purgeVerifyingCommand extends Command { +class PurgeVerifyingCommand extends Command { public constructor(context: Command.Context, options: Command.Options) { super(context, { ...options, @@ -129,3 +129,5 @@ export class purgeVerifyingCommand extends Command { */ } } + +export default PurgeVerifyingCommand; diff --git a/src/listeners/deniedPermission.ts b/src/listeners/deniedPermission.ts index e8952ef..fcbb1ad 100644 --- a/src/listeners/deniedPermission.ts +++ b/src/listeners/deniedPermission.ts @@ -20,7 +20,7 @@ import type { UserError, ChatInputCommandDeniedPayload } from '@sapphire/framework'; import { Listener } from '@sapphire/framework'; -export class CommandDeniedListener extends Listener { +class CommandDeniedListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { super(context, { ...options, @@ -33,3 +33,5 @@ export class CommandDeniedListener extends Listener { return interaction.reply(error.message); } } + +export default CommandDeniedListener; diff --git a/src/listeners/ready.ts b/src/listeners/ready.ts index 4befaf1..dc8415a 100644 --- a/src/listeners/ready.ts +++ b/src/listeners/ready.ts @@ -23,7 +23,7 @@ import { Listener } from '@sapphire/framework'; import type { Client } from 'discord.js'; -export class ReadyListener extends Listener { +class ReadyListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { super(context, { ...options, @@ -37,3 +37,5 @@ export class ReadyListener extends Listener { this.container.logger.info(`Successfully logged in as ${username} (${id})`); } } + +export default ReadyListener; diff --git a/src/preconditions/CoordinatorOnly.ts b/src/preconditions/CoordinatorOnly.ts index c067410..5a77f45 100644 --- a/src/preconditions/CoordinatorOnly.ts +++ b/src/preconditions/CoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class CoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class CoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { CoordinatorOnly: never; } } + +export default CoordinatorOnlyPrecondition; diff --git a/src/preconditions/DevCoordinatorOnly.ts b/src/preconditions/DevCoordinatorOnly.ts index aeeb3cd..fcd997b 100644 --- a/src/preconditions/DevCoordinatorOnly.ts +++ b/src/preconditions/DevCoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class DevCoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class DevCoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkDevCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { DevCoordinatorOnly: never; } } + +export default DevCoordinatorOnlyPrecondition; diff --git a/src/preconditions/DiversityCoordinatorOnly.ts b/src/preconditions/DiversityCoordinatorOnly.ts index 4e3ebbb..101db76 100644 --- a/src/preconditions/DiversityCoordinatorOnly.ts +++ b/src/preconditions/DiversityCoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class DiversityCoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class DiversityCoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkDiversityCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { DiversityCoordinatorOnly: never; } } + +export default DiversityCoordinatorOnlyPrecondition; diff --git a/src/preconditions/EventCoordinatorOnly.ts b/src/preconditions/EventCoordinatorOnly.ts index bdc76e0..2b76783 100644 --- a/src/preconditions/EventCoordinatorOnly.ts +++ b/src/preconditions/EventCoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class EventCoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class EventCoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkEventCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { EventCoordinatorOnly: never; } } + +export default EventCoordinatorOnlyPrecondition; diff --git a/src/preconditions/MentorCoordinatorOnly.ts b/src/preconditions/MentorCoordinatorOnly.ts index d0ebf7e..7a58bc5 100644 --- a/src/preconditions/MentorCoordinatorOnly.ts +++ b/src/preconditions/MentorCoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class MentorCoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class MentorCoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkMentorCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { MentorCoordinatorOnly: never; } } + +export default MentorCoordinatorOnlyPrecondition; diff --git a/src/preconditions/ModOnly.ts b/src/preconditions/ModOnly.ts index 3436688..d2618da 100644 --- a/src/preconditions/ModOnly.ts +++ b/src/preconditions/ModOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class ModOnlyPrecondition extends AllFlowsPrecondition { +class ModOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkMod(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { ModOnly: never; } } + +export default ModOnlyPrecondition; diff --git a/src/preconditions/PatreonOnly.ts b/src/preconditions/PatreonOnly.ts index 54ddc61..3428c0e 100644 --- a/src/preconditions/PatreonOnly.ts +++ b/src/preconditions/PatreonOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class PatreonOnlyPrecondition extends AllFlowsPrecondition { +class PatreonOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkPatreon(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { PatreonOnly: never; } } + +export default PatreonOnlyPrecondition; diff --git a/src/preconditions/VerifierCoordinatorOnly.ts b/src/preconditions/VerifierCoordinatorOnly.ts index bf9a347..c5d1214 100644 --- a/src/preconditions/VerifierCoordinatorOnly.ts +++ b/src/preconditions/VerifierCoordinatorOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class VerifierCoordinatorOnlyPrecondition extends AllFlowsPrecondition { +class VerifierCoordinatorOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkVerifierCoordinator(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { VerifierCoordinatorOnly: never; } } + +export default VerifierCoordinatorOnlyPrecondition; diff --git a/src/preconditions/VerifierOnly.ts b/src/preconditions/VerifierOnly.ts index e415bd3..1c5f8ee 100644 --- a/src/preconditions/VerifierOnly.ts +++ b/src/preconditions/VerifierOnly.ts @@ -26,7 +26,7 @@ import type { } from 'discord.js'; import IDs from '../utils/ids'; -export class VerifierOnlyPrecondition extends AllFlowsPrecondition { +class VerifierOnlyPrecondition extends AllFlowsPrecondition { public override async messageRun(message: Message) { // for message command return this.checkVerifier(message.member!); @@ -54,3 +54,5 @@ declare module '@sapphire/framework' { VerifierOnly: never; } } + +export default VerifierOnlyPrecondition; diff --git a/src/scheduled-tasks/appleWarning.ts b/src/scheduled-tasks/appleWarning.ts new file mode 100644 index 0000000..22305ac --- /dev/null +++ b/src/scheduled-tasks/appleWarning.ts @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; +import { container } from '@sapphire/framework'; +import type { TextChannel } from 'discord.js'; +import IDs from '../utils/ids'; + +class AppleWarningTask extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, { + ...options, + cron: '0 */2 * * 2-3', + }); + } + + public async run() { + const { client } = container; + + const channel = client.channels.cache.get(IDs.channels.nonVegan.general) as TextChannel; + + await channel.send('Hiya everyone, this is a warning to all **Apple users**!\n' + + 'Make sure to update your iOS, iPadOS and MacOS as there is a hack that lets anyone get remote access to your device if you click on a malicious link.\n' + + `For more information, read the post in <#${IDs.channels.information.news}>`); + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + cron: never; + } +} + +export default AppleWarningTask; diff --git a/src/scheduled-tasks/standup.ts b/src/scheduled-tasks/standup.ts index 9aef1bf..5645162 100644 --- a/src/scheduled-tasks/standup.ts +++ b/src/scheduled-tasks/standup.ts @@ -22,7 +22,7 @@ import { container } from '@sapphire/framework'; import type { TextChannel } from 'discord.js'; import IDs from '../utils/ids'; -export class StandupTask extends ScheduledTask { +class StandupTask extends ScheduledTask { public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { super(context, { ...options, @@ -45,3 +45,5 @@ declare module '@sapphire/plugin-scheduled-tasks' { cron: never; } } + +export default StandupTask; diff --git a/src/utils/dbExistingUser.ts b/src/utils/dbExistingUser.ts new file mode 100644 index 0000000..14a5892 --- /dev/null +++ b/src/utils/dbExistingUser.ts @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import type { GuildMember } from 'discord.js'; +import { PrismaClient } from '@prisma/client'; +import IDs from './ids'; + +// Checks if the user exists on the database +export async function userExists(user: GuildMember) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Counts if the user is on the database by their snowflake + const userQuery = await prisma.user.count({ + where: { + id: user.id, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + // If the user is found on the database, then return true, otherwise, false. + return userQuery > 0; +} + +// Adds the user to the database if they were already on the server before the bot/database +export async function addExistingUser(user: GuildMember) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Counts if the user is on the database by their snowflake + const userQuery = await prisma.user.count({ + where: { + id: user.id, + }, + }); + + // If the user is already in the database + if (userQuery > 0) { + return; + } + + // Checks what roles the user has + const hasVegan = user.roles.cache.has(IDs.roles.vegan.vegan); + const hasActivist = user.roles.cache.has(IDs.roles.vegan.activist); + const hasPlus = user.roles.cache.has(IDs.roles.vegan.plus); + const hasNotVegan = user.roles.cache.has(IDs.roles.nonvegan.nonvegan); + const hasVegCurious = user.roles.cache.has(IDs.roles.nonvegan.vegCurious); + const hasConvinced = user.roles.cache.has(IDs.roles.nonvegan.convinced); + const hasTrusted = user.roles.cache.has(IDs.roles.trusted); + const hasMuted = user.roles.cache.has(IDs.roles.restrictions.muted); + + // Create the user in the database + await prisma.user.create({ + data: { + id: user.id, + vegan: hasVegan, + trusted: hasTrusted, + activist: hasActivist, + plus: hasPlus, + notVegan: hasNotVegan, + vegCurious: hasVegCurious, + convinced: hasConvinced, + muted: hasMuted, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index 8c6bf60..9493355 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -57,11 +57,17 @@ const devIDs = { verifyBlock: '1007477161835372574', }, channels: { + information: { + news: '999431676058927247', + }, staff: { coordinators: '999431676058927254', standup: '999431676289622183', verifiers: '999431677006860411', }, + nonVegan: { + general: '999431677325615189', + }, diversity: { women: '999431679053660187', lgbtqia: '999431679053660188', diff --git a/src/utils/ids.ts b/src/utils/ids.ts index 15422be..81b9eef 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -19,6 +19,7 @@ import devIDs from './devIDs'; +// eslint-disable-next-line import/no-mutable-exports let IDs = { roles: { trusted: '731563158011117590', @@ -59,11 +60,17 @@ let IDs = { verifyBlock: '', }, channels: { + information: { + news: '866000393259319306', + }, staff: { coordinators: '1006240682505142354', standup: '996009201237233684', verifiers: '873215538627756072', }, + nonVegan: { + general: '798967615636504657', + }, diversity: { women: '938808963544285324', lgbtqia: '956224226556272670', From 75b768046d09d00ee4151f8fee05a796d361f31f Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 23 Aug 2022 02:13:35 +0100 Subject: [PATCH 20/57] feat(verification): add util config fixes --- src/commands/mod/sus.ts | 2 +- src/utils/database/dbExistingUser.ts | 11 ++-- src/utils/dbExistingUser.ts | 87 ---------------------------- src/utils/verificationConfig.ts | 21 +++++++ 4 files changed, 26 insertions(+), 95 deletions(-) delete mode 100644 src/utils/dbExistingUser.ts create mode 100644 src/utils/verificationConfig.ts diff --git a/src/commands/mod/sus.ts b/src/commands/mod/sus.ts index fb2d9d7..13f960f 100644 --- a/src/commands/mod/sus.ts +++ b/src/commands/mod/sus.ts @@ -23,7 +23,7 @@ import { } from 'discord.js'; import { PrismaClient } from '@prisma/client'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; -import { addExistingUser, userExists } from '../../utils/dbExistingUser'; +import { addExistingUser, userExists } from '../../utils/database/dbExistingUser'; import IDs from '../../utils/ids'; // TODO add a check when they join the server to give the user the sus role again diff --git a/src/utils/database/dbExistingUser.ts b/src/utils/database/dbExistingUser.ts index 36f5c62..b86824b 100644 --- a/src/utils/database/dbExistingUser.ts +++ b/src/utils/database/dbExistingUser.ts @@ -27,7 +27,7 @@ export async function userExists(user: GuildMember) { const prisma = new PrismaClient(); // Counts if the user is on the database by their snowflake - const userExists = await prisma.user.count({ + const userQuery = await prisma.user.count({ where: { id: user.id, }, @@ -37,10 +37,7 @@ export async function userExists(user: GuildMember) { await prisma.$disconnect(); // If the user is found on the database, then return true, otherwise, false. - if (userExists > 0) { - return true; - } - return false; + return userQuery > 0; } function getRoles(roles: GuildMemberRoleManager) { @@ -65,14 +62,14 @@ export async function addExistingUser(user: GuildMember) { const prisma = new PrismaClient(); // Counts if the user is on the database by their snowflake - const userExists = await prisma.user.count({ + const userQuery = await prisma.user.count({ where: { id: user.id, }, }); // If the user is already in the database - if (userExists > 0) { + if (userQuery > 0) { return; } diff --git a/src/utils/dbExistingUser.ts b/src/utils/dbExistingUser.ts deleted file mode 100644 index 14a5892..0000000 --- a/src/utils/dbExistingUser.ts +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - Animal Rights Advocates Discord Bot - Copyright (C) 2022 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 . -*/ - -import type { GuildMember } from 'discord.js'; -import { PrismaClient } from '@prisma/client'; -import IDs from './ids'; - -// Checks if the user exists on the database -export async function userExists(user: GuildMember) { - // Initialises Prisma Client - const prisma = new PrismaClient(); - - // Counts if the user is on the database by their snowflake - const userQuery = await prisma.user.count({ - where: { - id: user.id, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - - // If the user is found on the database, then return true, otherwise, false. - return userQuery > 0; -} - -// Adds the user to the database if they were already on the server before the bot/database -export async function addExistingUser(user: GuildMember) { - // Initialises Prisma Client - const prisma = new PrismaClient(); - - // Counts if the user is on the database by their snowflake - const userQuery = await prisma.user.count({ - where: { - id: user.id, - }, - }); - - // If the user is already in the database - if (userQuery > 0) { - return; - } - - // Checks what roles the user has - const hasVegan = user.roles.cache.has(IDs.roles.vegan.vegan); - const hasActivist = user.roles.cache.has(IDs.roles.vegan.activist); - const hasPlus = user.roles.cache.has(IDs.roles.vegan.plus); - const hasNotVegan = user.roles.cache.has(IDs.roles.nonvegan.nonvegan); - const hasVegCurious = user.roles.cache.has(IDs.roles.nonvegan.vegCurious); - const hasConvinced = user.roles.cache.has(IDs.roles.nonvegan.convinced); - const hasTrusted = user.roles.cache.has(IDs.roles.trusted); - const hasMuted = user.roles.cache.has(IDs.roles.restrictions.muted); - - // Create the user in the database - await prisma.user.create({ - data: { - id: user.id, - vegan: hasVegan, - trusted: hasTrusted, - activist: hasActivist, - plus: hasPlus, - notVegan: hasNotVegan, - vegCurious: hasVegCurious, - convinced: hasConvinced, - muted: hasMuted, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts new file mode 100644 index 0000000..0416129 --- /dev/null +++ b/src/utils/verificationConfig.ts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +// eslint-disable-next-line import/prefer-default-export +export const maxVCs = 10; From 3dd219ae04ca473bcaf6ff00f8a0aec40873990c Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 23 Aug 2022 04:31:03 +0100 Subject: [PATCH 21/57] feat(verification): add being able to go through questions --- src/listeners/verification/joinVC.ts | 111 +++++++++++---------------- src/utils/verificationConfig.ts | 50 +++++++++++- 2 files changed, 94 insertions(+), 67 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 6ecff41..827b3b8 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -19,12 +19,12 @@ import { container, Listener } from '@sapphire/framework'; import type { - VoiceChannel, CategoryChannel, - VoiceState, - TextChannel, - GuildMember, ColorResolvable, + GuildMember, + TextChannel, + VoiceChannel, + VoiceState, } from 'discord.js'; import { ButtonInteraction, @@ -33,7 +33,7 @@ import { MessageButton, MessageEmbed, } from 'discord.js'; -import { maxVCs } from '../../utils/verificationConfig'; +import { maxVCs, questionInfo } from '../../utils/verificationConfig'; import { joinVerification, startVerification } from '../../utils/database/verification'; import IDs from '../../utils/ids'; @@ -111,7 +111,8 @@ class VerificationJoinVCListener extends Listener { verifier = true; } else { await channel.setName(`${member.displayName} - Verification`); - await currentChannel.send(`Hiya ${member.user}, please be patient as a verifier has been called out to verify you.\n\nIf you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you'd like to verify as a vegan again, you'd have to contact a Mod, which could be done via ModMail.`); + await currentChannel.send(`Hiya ${member.user}, please be patient as a verifier has been called out to verify you.\n\n` + + 'If you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you\'d like to verify as a vegan again, you\'d have to contact a Mod, which could be done via ModMail.'); // Adds to the database that the user joined verification await joinVerification(member, channel.id); } @@ -230,7 +231,7 @@ class VerificationJoinVCListener extends Listener { const embedColor = '#0099ff'; const { displayName } = user; console.log(displayName); // TODO remove this - literally just used to shut up TypeScript - let info = { + const info = { page: 0, find: { reason: 0, @@ -250,61 +251,12 @@ class VerificationJoinVCListener extends Listener { }; // TODO add a variable that tells if each order has a reversed value, e.g. 0-3 or 3-0 - const questionInfo = [ - { - question: 'Welcome to Animal Rights Advocates! How did you find the server?', - buttons: [ - 'Friend', - 'YouTube', - 'Another Server', - 'Vegan Org', - ], - }, - { - question: 'How long have you been vegan?', - buttons: [ - '<1 month', - '1-2 months', - '3-6 months', - '6 months – 1 year', - '1-2 years', - '2+ years', - ], - }, - { - question: 'Ask the user why they went vegan and to define veganism.\n' - + 'Do they cite ethical concerns and abstinence from at least meat, dairy, eggs, leather, and fur?', - buttons: [ - 'Yes', - 'Yes with prompting', - 'No', - ], - }, - { - question: 'Ask the user about their life as a vegan, including things like watching documentaries or social media content and interactions with family and friends. What are their stories like?', - buttons: [ - 'Believable', - 'Unbelievable', - 'Short', - ], - }, - { - question: 'Ask the user about food and nutrition. Do they seem to know how to live as a vegan?', - buttons: [ - 'Dietitian / Chef', - 'Acceptable', - 'Salads / Smoothies', - 'No clue', - ], - }, - ]; + const questionLength = questionInfo.length; // Create an embeds for each page - /* - const initialEmbed = new MessageEmbed() + const veganEmbed = new MessageEmbed() .setColor(embedColor) .setTitle(`Do you think ${displayName} is definitely vegan?`); - */ const activistEmbed = new MessageEmbed() .setColor(embedColor) @@ -318,7 +270,7 @@ class VerificationJoinVCListener extends Listener { const vegCuriousEmbed = new MessageEmbed() .setColor(embedColor) .setTitle('Should this user get Veg Curious?'); - + */ // Create buttons to delete or cancel the deletion const initialButtons = new MessageActionRow() @@ -332,7 +284,6 @@ class VerificationJoinVCListener extends Listener { .setLabel('No') .setStyle(Constants.MessageButtonStyles.DANGER), ); - */ const activistButtons = new MessageActionRow() .addComponents( @@ -376,8 +327,8 @@ class VerificationJoinVCListener extends Listener { ); */ - const embed = await this.createEmbed(questionInfo[0].question, embedColor); - const buttons = await this.createButtons(questionInfo[0].buttons); + let embed = await this.createEmbed(questionInfo[0].question, embedColor); + let buttons = await this.createButtons(questionInfo[0].buttons); // Sends the note to verify this note is to be deleted const message = await channel.send({ @@ -387,12 +338,42 @@ class VerificationJoinVCListener extends Listener { // Listen for the button presses const collector = channel.createMessageComponentCollector({ - max: 2, // Maximum of 1 button press + // max: 2, // Maximum of 1 button press }); // Button pressed collector.on('collect', async (button: ButtonInteraction) => { // Select roles + if (button.customId.includes('button')) { + await button.deferUpdate(); + /* + const buttonChoice = button.customId.at(button.customId.length - 1); + switch (buttonChoice) { + case 1: { + info.length = buttonChoice; + break; + } + case 2: { + + } + } + */ + info.page += 1; + // Checks if finished all the questions + if (info.page < questionLength) { + embed = await this.createEmbed(questionInfo[info.page].question, embedColor); + buttons = await this.createButtons(questionInfo[info.page].buttons); + await message.edit({ + embeds: [embed], + components: [buttons], + }); + } else { + await message.edit({ + embeds: [veganEmbed], + components: [initialButtons], + }); + } + } // Definitely vegan? if (button.customId === `yesVegan${id}`) { await button.deferUpdate(); @@ -414,11 +395,9 @@ class VerificationJoinVCListener extends Listener { } private async createEmbed(title: string, color: ColorResolvable) { - const embed = new MessageEmbed() + return new MessageEmbed() .setColor(color) .setTitle(title); - - return embed; } private async createButtons(buttons: string[]) { diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts index 0416129..5c6b6d9 100644 --- a/src/utils/verificationConfig.ts +++ b/src/utils/verificationConfig.ts @@ -17,5 +17,53 @@ along with this program. If not, see . */ -// eslint-disable-next-line import/prefer-default-export export const maxVCs = 10; + +export const questionInfo = [ + { + question: 'Welcome to Animal Rights Advocates! How did you find the server?', + buttons: [ + 'Friend', + 'YouTube', + 'Another Server', + 'Vegan Org', + ], + }, + { + question: 'How long have you been vegan?', + buttons: [ + '<1 month', + // '1-2 months', + '3-6 months', + '6 months - 1 year', + '1-2 years', + '2+ years', + ], + }, + { + question: 'Ask the user why they went vegan and to define veganism.\n' + + 'Do they cite ethical concerns and abstinence from at least meat, dairy, eggs, leather, and fur?', + buttons: [ + 'Yes', + 'Yes with prompting', + 'No', + ], + }, + { + question: 'Ask the user about their life as a vegan, including things like watching documentaries or social media content and interactions with family and friends. What are their stories like?', + buttons: [ + 'Believable', + 'Unbelievable', + 'Short', + ], + }, + { + question: 'Ask the user about food and nutrition. Do they seem to know how to live as a vegan?', + buttons: [ + 'Dietitian / Chef', + 'Acceptable', + 'Salads / Smoothies', + 'No clue', + ], + }, +]; From 39c32101c517754d21f9d1380a84bbdefff496e1 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 23 Aug 2022 04:32:07 +0100 Subject: [PATCH 22/57] build(config): add prisma as dev dependency --- package-lock.json | 10 +++++++--- package.json | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index f9d49d9..f45f4db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,6 @@ "discord-api-types": "^0.33.3", "discord.js": "^13.10.3", "dotenv": "^16.0.1", - "prisma": "^4.2.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" }, @@ -33,7 +32,8 @@ "eslint": "^8.20.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-import": "^2.26.0" + "eslint-plugin-import": "^2.26.0", + "prisma": "^4.2.1" } }, "node_modules/@cspotcode/source-map-support": { @@ -284,6 +284,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { @@ -2691,6 +2692,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "devOptional": true, "hasInstallScript": true, "dependencies": { "@prisma/engines": "4.2.1" @@ -3484,7 +3486,8 @@ "@prisma/engines": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", - "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==" + "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "devOptional": true }, "@prisma/engines-version": { "version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826", @@ -5238,6 +5241,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "devOptional": true, "requires": { "@prisma/engines": "4.2.1" } diff --git a/package.json b/package.json index 77430ba..39ae8c9 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "discord-api-types": "^0.33.3", "discord.js": "^13.10.3", "dotenv": "^16.0.1", - "prisma": "^4.2.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" }, @@ -50,6 +49,7 @@ "eslint": "^8.20.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", - "eslint-plugin-import": "^2.26.0" + "eslint-plugin-import": "^2.26.0", + "prisma": "^4.2.1" } } From 41c23ebb3cd95b5c7ef9e6d6a919e173c07c9525 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 02:05:35 +0100 Subject: [PATCH 23/57] feat(verification): add logging button presses --- src/listeners/verification/joinVC.ts | 49 ++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 827b3b8..8fd986c 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -346,19 +346,39 @@ class VerificationJoinVCListener extends Listener { // Select roles if (button.customId.includes('button')) { await button.deferUpdate(); - /* - const buttonChoice = button.customId.at(button.customId.length - 1); - switch (buttonChoice) { - case 1: { - info.length = buttonChoice; - break; - } - case 2: { - + // Get the button choice + const buttonChoice = this.getButtonValue(button.customId); + if (!isNaN(buttonChoice)) { + // Set the value of the button choice to the page the question was on + switch (info.page) { + case 0: { + info.find.reason = buttonChoice; + break; + } + case 1: { + info.length = buttonChoice; + break; + } + case 2: { + info.reasoning = buttonChoice; + break; + } + case 3: { + info.life = buttonChoice; + break; + } + case 4: { + info.food = buttonChoice; + break; + } + default: { + console.error('Button clicked out of range'); + break; + } } } - */ info.page += 1; + console.log(info); // Checks if finished all the questions if (info.page < questionLength) { embed = await this.createEmbed(questionInfo[info.page].question, embedColor); @@ -415,6 +435,15 @@ class VerificationJoinVCListener extends Listener { return buttonAction; } + + // Finds the value of the choice in the butotn + private getButtonValue(button: string) { + const buttonChoice = button.at(button.length - 1); + if (buttonChoice === undefined) { + return NaN; + } + return parseInt(buttonChoice, 10); + } } export default VerificationJoinVCListener; From 4deb7efc56d4212062b1f76cf0c33e25da469926 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 02:58:45 +0100 Subject: [PATCH 24/57] feat(verification): add ability for up to 25 buttons --- src/listeners/verification/joinVC.ts | 18 ++++++++++-------- src/utils/verificationConfig.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 8fd986c..c5d4019 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -230,7 +230,6 @@ class VerificationJoinVCListener extends Listener { ) { const embedColor = '#0099ff'; const { displayName } = user; - console.log(displayName); // TODO remove this - literally just used to shut up TypeScript const info = { page: 0, find: { @@ -333,7 +332,7 @@ class VerificationJoinVCListener extends Listener { // Sends the note to verify this note is to be deleted const message = await channel.send({ embeds: [embed], - components: [buttons], + components: buttons, }); // Listen for the button presses @@ -378,14 +377,13 @@ class VerificationJoinVCListener extends Listener { } } info.page += 1; - console.log(info); // Checks if finished all the questions if (info.page < questionLength) { embed = await this.createEmbed(questionInfo[info.page].question, embedColor); buttons = await this.createButtons(questionInfo[info.page].buttons); await message.edit({ embeds: [embed], - components: [buttons], + components: buttons, }); } else { await message.edit({ @@ -421,10 +419,14 @@ class VerificationJoinVCListener extends Listener { } private async createButtons(buttons: string[]) { - const buttonAction = new MessageActionRow(); + const buttonActions = []; for (let i = 0; i < buttons.length; i += 1) { - buttonAction + // Check if it exceeds the maximum buttons in a ActionRow + if (i % 5 === 0) { + buttonActions.push(new MessageActionRow()); + } + buttonActions[Math.floor(i / 5)] .addComponents( new MessageButton() .setCustomId(`button${i}`) @@ -433,10 +435,10 @@ class VerificationJoinVCListener extends Listener { ); } - return buttonAction; + return buttonActions; } - // Finds the value of the choice in the butotn + // Finds the value of the choice in the button private getButtonValue(button: string) { const buttonChoice = button.at(button.length - 1); if (buttonChoice === undefined) { diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts index 5c6b6d9..fe6efe4 100644 --- a/src/utils/verificationConfig.ts +++ b/src/utils/verificationConfig.ts @@ -33,7 +33,7 @@ export const questionInfo = [ question: 'How long have you been vegan?', buttons: [ '<1 month', - // '1-2 months', + '1-2 months', '3-6 months', '6 months - 1 year', '1-2 years', From 801297c3a1b589290d06f4a37028894157773428 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 14:55:55 +0100 Subject: [PATCH 25/57] feat(verification): last few questions are dynamically added --- src/listeners/verification/joinVC.ts | 192 ++++++++++----------------- src/utils/verificationConfig.ts | 68 ++++++++++ 2 files changed, 137 insertions(+), 123 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index c5d4019..dbf6453 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -21,7 +21,6 @@ import { container, Listener } from '@sapphire/framework'; import type { CategoryChannel, ColorResolvable, - GuildMember, TextChannel, VoiceChannel, VoiceState, @@ -33,7 +32,7 @@ import { MessageButton, MessageEmbed, } from 'discord.js'; -import { maxVCs, questionInfo } from '../../utils/verificationConfig'; +import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; import { joinVerification, startVerification } from '../../utils/database/verification'; import IDs from '../../utils/ids'; @@ -148,7 +147,7 @@ class VerificationJoinVCListener extends Listener { await verificationText.send(`${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); - await this.verificationProcess(member, verificationText, channel.id); + await this.verificationProcess(verificationText); } // Create a new channel for others to join @@ -224,12 +223,9 @@ class VerificationJoinVCListener extends Listener { } private async verificationProcess( - user: GuildMember, channel: TextChannel, - id: string, ) { const embedColor = '#0099ff'; - const { displayName } = user; const info = { page: 0, find: { @@ -252,80 +248,6 @@ class VerificationJoinVCListener extends Listener { // TODO add a variable that tells if each order has a reversed value, e.g. 0-3 or 3-0 const questionLength = questionInfo.length; - // Create an embeds for each page - const veganEmbed = new MessageEmbed() - .setColor(embedColor) - .setTitle(`Do you think ${displayName} is definitely vegan?`); - - const activistEmbed = new MessageEmbed() - .setColor(embedColor) - .setTitle('Offer to ask questions for Activist. Do you think they should get it?'); - - const noActivistEmbed = new MessageEmbed() - .setColor(embedColor) - .setTitle('Do some activism, asking Activist questions. Now which role should they get?'); - - /* - const vegCuriousEmbed = new MessageEmbed() - .setColor(embedColor) - .setTitle('Should this user get Veg Curious?'); - */ - - // Create buttons to delete or cancel the deletion - const initialButtons = new MessageActionRow() - .addComponents( - new MessageButton() - .setCustomId(`yesVegan${id}`) - .setLabel('Yes') - .setStyle(Constants.MessageButtonStyles.SUCCESS), - new MessageButton() - .setCustomId(`noVegan${id}`) - .setLabel('No') - .setStyle(Constants.MessageButtonStyles.DANGER), - ); - - const activistButtons = new MessageActionRow() - .addComponents( - new MessageButton() - .setCustomId(`yesActivist${id}`) - .setLabel('Yes') - .setStyle(Constants.MessageButtonStyles.SUCCESS), - new MessageButton() - .setCustomId(`noActivist${id}`) - .setLabel('No') - .setStyle(Constants.MessageButtonStyles.DANGER), - ); - - const noActivistButtons = new MessageActionRow() - .addComponents( - new MessageButton() - .setCustomId(`vegan${id}`) - .setLabel('Vegan') - .setStyle(Constants.MessageButtonStyles.SUCCESS), - new MessageButton() - .setCustomId(`convinced${id}`) - .setLabel('Convinced') - .setStyle(Constants.MessageButtonStyles.SECONDARY), - new MessageButton() - .setCustomId(`notVegan${id}`) - .setLabel('Non-vegan') - .setStyle(Constants.MessageButtonStyles.DANGER), - ); - - /* - const vegCuriousButtons = new MessageActionRow() - .addComponents( - new MessageButton() - .setCustomId(`yesVegCurious${id}`) - .setLabel('Yes') - .setStyle(Constants.MessageButtonStyles.SUCCESS), - new MessageButton() - .setCustomId(`noVegCurious${id}`) - .setLabel('No') - .setStyle(Constants.MessageButtonStyles.DANGER), - ); - */ - let embed = await this.createEmbed(questionInfo[0].question, embedColor); let buttons = await this.createButtons(questionInfo[0].buttons); @@ -347,33 +269,79 @@ class VerificationJoinVCListener extends Listener { await button.deferUpdate(); // Get the button choice const buttonChoice = this.getButtonValue(button.customId); - if (!isNaN(buttonChoice)) { - // Set the value of the button choice to the page the question was on - switch (info.page) { - case 0: { - info.find.reason = buttonChoice; - break; + if (isNaN(buttonChoice)) { + return; + } + // Set the value of the button choice to the page the question was on + switch (info.page) { + case 0: { + info.find.reason = buttonChoice; + if (buttonChoice !== 0) { + embed = await this.createEmbed(serverFind[info.page].question, embedColor); + buttons = await this.createButtons(serverFind[info.page].buttons); + await message.edit({ + embeds: [embed], + components: buttons, + }); + return; } - case 1: { - info.length = buttonChoice; - break; + if (info.find.reason !== 0) { + info.find.where = buttonChoice; } - case 2: { - info.reasoning = buttonChoice; - break; + break; + } + case 1: { + info.length = buttonChoice; + break; + } + case 2: { + info.reasoning = buttonChoice; + break; + } + case 3: { + info.life = buttonChoice; + break; + } + case 4: { + info.food = buttonChoice; + break; + } + // If they are definitely vegan or not + case 5: { + if (buttonChoice === 0) { + info.roles.vegan = true; + info.roles.trusted = true; + } else { + info.page += 1; } - case 3: { - info.life = buttonChoice; - break; + break; + } + // If they are vegan but should get activist role + case 6: { + if (buttonChoice === 0) { + info.roles.activist = true; } - case 4: { - info.food = buttonChoice; - break; + info.page += 1; + break; + } + // If they should get vegan, convinced or non-vegan + case 7: { + if (buttonChoice === 0) { + info.roles.vegan = true; + } else if (buttonChoice === 1) { + info.roles.convinced = true; } - default: { - console.error('Button clicked out of range'); - break; + break; + } + case 8: { + if (buttonChoice === 0) { + info.roles.vegCurious = true; } + break; + } + default: { + console.error('Button clicked out of range'); + return; } } info.page += 1; @@ -385,30 +353,8 @@ class VerificationJoinVCListener extends Listener { embeds: [embed], components: buttons, }); - } else { - await message.edit({ - embeds: [veganEmbed], - components: [initialButtons], - }); } } - // Definitely vegan? - if (button.customId === `yesVegan${id}`) { - await button.deferUpdate(); - info.roles.vegan = true; - await message.edit({ - embeds: [activistEmbed], - components: [activistButtons], - }); - } - // Not as vegan - if (button.customId === `noVegan${id}`) { - await button.deferUpdate(); - await message.edit({ - embeds: [noActivistEmbed], - components: [noActivistButtons], - }); - } }); } diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts index fe6efe4..1b5a7db 100644 --- a/src/utils/verificationConfig.ts +++ b/src/utils/verificationConfig.ts @@ -23,6 +23,7 @@ export const questionInfo = [ { question: 'Welcome to Animal Rights Advocates! How did you find the server?', buttons: [ + 'Search', 'Friend', 'YouTube', 'Another Server', @@ -66,4 +67,71 @@ export const questionInfo = [ 'No clue', ], }, + { + question: 'Do you think this user is definitely vegan?', + buttons: [ + 'Yes', + 'No', + ], + }, + { + question: 'Offer to ask questions for Activist. Do you think they should get it?', + buttons: [ + 'Yes', + 'No', + ], + }, + { + question: 'Do some activism, asking Activist questions. Now which role should they get?', + buttons: [ + 'Vegan', + 'Convinced', + 'Non-vegan', + ], + }, + { + question: 'Should this user get Veg Curious?', + buttons: [ + 'Yes', + 'No', + ], + }, +]; + +export const serverFind = [ + // From a friend + { + question: 'Ask for username and indicate', + buttons: [ + 'Vegan', + 'Non-Vegan', + 'Unknown', + ], + }, + // From a video + { + question: 'Ask what video', + buttons: [ + 'Troll video', + 'Our content', + 'Other', + ], + }, + // From another server + { + question: 'Ask which server', + buttons: [ + 'Vegan', + 'Debate', + 'Other', + ], + }, + // From a vegan organisation + { + question: 'Ask which one', + buttons: [ + 'Vegan Hacktivists', + 'Other', + ], + }, ]; From 6af8373f2b84a0c97b7019f626d5e98e23fb71a0 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 15:01:01 +0100 Subject: [PATCH 26/57] fix(verification): isNaN eslint issue --- src/listeners/verification/joinVC.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index dbf6453..a9f0b04 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -269,7 +269,7 @@ class VerificationJoinVCListener extends Listener { await button.deferUpdate(); // Get the button choice const buttonChoice = this.getButtonValue(button.customId); - if (isNaN(buttonChoice)) { + if (Number.isNaN(buttonChoice)) { return; } // Set the value of the button choice to the page the question was on From a4d15f67ab1be5754cc2c435042750398c00b0b6 Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 15:12:27 +0100 Subject: [PATCH 27/57] ci(compiler): update target from es2016 to es2021 --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 59e91d1..659c12b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ From b71a7ef2eaf6a0160e3e8c3553c9bd807b0c7f0b Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 24 Aug 2022 15:34:57 +0100 Subject: [PATCH 28/57] ci(config): update docker node debian version --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c9b3a48..c6003ff 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:18-buster +FROM node:18 WORKDIR /opt/app From 0043fdddfbbfe041fe2c4ddff26a3b193ef1f5ad Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 27 Aug 2022 02:48:08 +0100 Subject: [PATCH 29/57] feat(verification): confirm add roles --- prisma/schema.prisma | 14 +++- src/listeners/verification/joinVC.ts | 116 ++++++++++++++++++++++++++- src/utils/database/verification.ts | 82 ++++++++----------- 3 files changed, 158 insertions(+), 54 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 24daf5f..3e4f17f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -57,10 +57,22 @@ model Verify { startTime DateTime? finishTime DateTime? timedOut Boolean @default(false) // If they got kicked out of verification because they timed out - //incomplete Boolean @default(false) // If the verification was incomplete + //complete Boolean @default(false) // If the verification was incomplete + // Roles they got from verification vegan Boolean @default(false) // If they got verified as a vegan + activist Boolean @default(false) // If they got the activist role when they verified + trusted Boolean @default(false) // If they got the trusted role when they verified + vegCurious Boolean @default(false) // If they got the Veg Curious role + convinced Boolean @default(false) text Boolean @default(false) // If they used text verification serverVegan Boolean @default(false) // People that went vegan on the server + // Stats on verification + reason Int? + where Int? + length Int? + reasoning Int? + life Int? + food Int? notes String? } diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index a9f0b04..af012b1 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -24,6 +24,7 @@ import type { TextChannel, VoiceChannel, VoiceState, + GuildMember, } from 'discord.js'; import { ButtonInteraction, @@ -33,7 +34,7 @@ import { MessageEmbed, } from 'discord.js'; import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; -import { joinVerification, startVerification } from '../../utils/database/verification'; +import { joinVerification, startVerification, finishVerification } from '../../utils/database/verification'; import IDs from '../../utils/ids'; class VerificationJoinVCListener extends Listener { @@ -93,7 +94,7 @@ class VerificationJoinVCListener extends Listener { return; } - await startVerification(member, channel.id); + await startVerification(channel.id); return; } @@ -113,7 +114,7 @@ class VerificationJoinVCListener extends Listener { await currentChannel.send(`Hiya ${member.user}, please be patient as a verifier has been called out to verify you.\n\n` + 'If you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you\'d like to verify as a vegan again, you\'d have to contact a Mod, which could be done via ModMail.'); // Adds to the database that the user joined verification - await joinVerification(member, channel.id); + await joinVerification(channel.id, member); } // Check how many voice channels there are @@ -147,7 +148,7 @@ class VerificationJoinVCListener extends Listener { await verificationText.send(`${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); - await this.verificationProcess(verificationText); + await this.verificationProcess(verificationText, channel.id, member); } // Create a new channel for others to join @@ -224,6 +225,8 @@ class VerificationJoinVCListener extends Listener { private async verificationProcess( channel: TextChannel, + verId: string, + user: GuildMember, ) { const embedColor = '#0099ff'; const info = { @@ -354,6 +357,50 @@ class VerificationJoinVCListener extends Listener { components: buttons, }); } + // Confirmation to give roles to the user being verified + if (info.page === questionLength) { + // Create embed with all the roles the user has + embed = new MessageEmbed() + .setColor(embedColor) + .setTitle(`Give these roles to ${user.displayName}?`) + .setThumbnail(user.avatarURL()!) + .addFields( + { name: 'Roles:', value: this.getTextRoles(info.roles) }, + ); + + // Create buttons for input + buttons = [new MessageActionRow() + .addComponents( + new MessageButton() + .setCustomId('confirm') + .setLabel('Yes') + .setStyle(Constants.MessageButtonStyles.SUCCESS), + new MessageButton() + .setCustomId('cancel') + .setLabel('No') + .setStyle(Constants.MessageButtonStyles.DANGER), + )]; + await message.edit({ + embeds: [embed], + components: buttons, + }); + } + } + // Confirming and finishing the verification + if (button.customId === 'confirm' && info.page >= questionLength) { + await finishVerification(verId, info); + await this.giveRoles(user, info.roles); + embed = new MessageEmbed() + .setColor('#34c000') + .setTitle(`Successfully verified ${user.displayName}!`) + .setThumbnail(user.avatarURL()!) + .addFields( + { name: 'Roles:', value: this.getTextRoles(info.roles) }, + ); + await message.edit({ + embeds: [embed], + components: [], + }); } }); } @@ -392,6 +439,67 @@ class VerificationJoinVCListener extends Listener { } return parseInt(buttonChoice, 10); } + + private getTextRoles( + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + ) { + let rolesText = ''; + if (roles.convinced) { + rolesText += `<@&${IDs.roles.nonvegan.convinced}>`; + } + if (roles.vegan) { + rolesText += `<@&${IDs.roles.vegan.vegan}>`; + } else { + rolesText += `<@&${IDs.roles.nonvegan.nonvegan}>`; + } + if (roles.activist) { + rolesText += `<@&${IDs.roles.vegan.activist}>`; + } + if (roles.trusted) { + rolesText += `<@&${IDs.roles.trusted}>`; + } + if (roles.vegCurious) { + rolesText += `<@&${IDs.roles.nonvegan.vegCurious}>`; + } + return rolesText; + } + + private async giveRoles( + user: GuildMember, + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + ) { + const rolesAdd = []; + if (roles.convinced) { + rolesAdd.push(IDs.roles.nonvegan.convinced); + } + if (roles.vegan) { + rolesAdd.push(IDs.roles.vegan.vegan); + } else { + rolesAdd.push(IDs.roles.nonvegan.nonvegan); + } + if (roles.activist) { + rolesAdd.push(IDs.roles.vegan.activist); + } + if (roles.trusted) { + rolesAdd.push(IDs.roles.trusted); + } + if (roles.vegCurious) { + rolesAdd.push(IDs.roles.nonvegan.vegCurious); + } + await user.roles.add(rolesAdd); + } } export default VerificationJoinVCListener; diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index b7ff13b..a0e6e4b 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -21,7 +21,7 @@ import type { GuildMember } from 'discord.js'; import { PrismaClient } from '@prisma/client'; import { updateUser } from './dbExistingUser'; -export async function joinVerification(user: GuildMember, channelId: string) { +export async function joinVerification(channelId: string, user: GuildMember) { // Update the user on the database with the current roles they have await updateUser(user); @@ -43,7 +43,7 @@ export async function joinVerification(user: GuildMember, channelId: string) { await prisma.$disconnect(); } -export async function startVerification(verifier: GuildMember, channelId: string) { +export async function startVerification(channelId: string) { // Initialises Prisma Client const prisma = new PrismaClient(); @@ -52,11 +52,6 @@ export async function startVerification(verifier: GuildMember, channelId: string id: channelId, }, data: { - verifier: { - connect: { - id: verifier.id, - }, - }, startTime: new Date(), }, }); @@ -93,61 +88,50 @@ export async function getUser(channelId: string) { export async function finishVerification( channelId: string, - timedOut: boolean, - vegan: boolean, - text:boolean, - serverVegan: boolean, + info: { + page: number, + find: { + reason: number, + where: number + }, + length: number, + reasoning: number, + life: number, + food: number, + roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + } }, ) { // Initialises Prisma Client const prisma = new PrismaClient(); - /* - const user = await prisma.verify.findUnique({ - where: { - id: channelId, - }, - select: { - userId: true, - }, - }); - */ - // TODO potentially add an incomplete tracker? await prisma.verify.update({ where: { id: channelId, }, data: { - timedOut, - vegan, - text, - serverVegan, + finishTime: new Date(), + // Roles + vegan: info.roles.vegan, + activist: info.roles.activist, + trusted: info.roles.trusted, + vegCurious: info.roles.vegCurious, + convinced: info.roles.convinced, + // Statistics + reason: info.find.reason, + where: info.find.where, + length: info.length, + reasoning: info.reasoning, + life: info.life, + food: info.food, }, }); // Close database connection await prisma.$disconnect(); - - // TODO add a way to give roles back after adding the new verification - /* - const roles = await fetchRoles(user!.userId); - - if (roles === null) { - return; - } - - // Give roles to the user - const giveRoles = []; - if (roles.trusted) { - giveRoles.push(IDs.roles.trusted); - } - if (roles.plus) { - giveRoles.push(IDs.roles.vegan.plus); - } - if (roles.vegCurious) { - giveRoles.push(IDs.roles.nonvegan.vegCurious); - } - - await user.roles.add(giveRoles); - */ } From 544d6bafd8d8686a56a2f5e64910c2be4a42e2c7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 27 Aug 2022 03:41:06 +0100 Subject: [PATCH 30/57] feat(verification): add verifier to database after confirmation --- src/listeners/verification/joinVC.ts | 23 ++++++++++++++++++++--- src/utils/database/verification.ts | 6 ++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index af012b1..390aa5e 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -25,6 +25,7 @@ import type { VoiceChannel, VoiceState, GuildMember, + Guild, } from 'discord.js'; import { ButtonInteraction, @@ -35,6 +36,7 @@ import { } from 'discord.js'; import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; import { joinVerification, startVerification, finishVerification } from '../../utils/database/verification'; +import { userExists, addExistingUser } from '../../utils/database/dbExistingUser'; import IDs from '../../utils/ids'; class VerificationJoinVCListener extends Listener { @@ -148,7 +150,7 @@ class VerificationJoinVCListener extends Listener { await verificationText.send(`${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); - await this.verificationProcess(verificationText, channel.id, member); + await this.verificationProcess(verificationText, channel.id, member, guild); } // Create a new channel for others to join @@ -227,6 +229,7 @@ class VerificationJoinVCListener extends Listener { channel: TextChannel, verId: string, user: GuildMember, + guild: Guild, ) { const embedColor = '#0099ff'; const info = { @@ -279,7 +282,7 @@ class VerificationJoinVCListener extends Listener { switch (info.page) { case 0: { info.find.reason = buttonChoice; - if (buttonChoice !== 0) { + if (buttonChoice !== 0 && info.find.reason === 0) { embed = await this.createEmbed(serverFind[info.page].question, embedColor); buttons = await this.createButtons(serverFind[info.page].buttons); await message.edit({ @@ -388,8 +391,22 @@ class VerificationJoinVCListener extends Listener { } // Confirming and finishing the verification if (button.customId === 'confirm' && info.page >= questionLength) { - await finishVerification(verId, info); + // Check verifier is on the database + const verifierGuildMember = await guild.members.cache.get(button.user.id); + if (verifierGuildMember === undefined) { + await message.edit({ content: 'Verifier not found!' }); + return; + } + // Add verifier to database if they're not on the database + if (!(await userExists(verifierGuildMember))) { + await addExistingUser(verifierGuildMember); + } + + // Add verification data to database + await finishVerification(verId, button.user.id, info); + // Give roles on Discord await this.giveRoles(user, info.roles); + // Add embed saying verification completed embed = new MessageEmbed() .setColor('#34c000') .setTitle(`Successfully verified ${user.displayName}!`) diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index a0e6e4b..e533f92 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -88,6 +88,7 @@ export async function getUser(channelId: string) { export async function finishVerification( channelId: string, + verifierId: string, info: { page: number, find: { @@ -115,6 +116,11 @@ export async function finishVerification( id: channelId, }, data: { + verifier: { + connect: { + id: verifierId, + }, + }, finishTime: new Date(), // Roles vegan: info.roles.vegan, From 63bce0d405e4a763e40fd96e79b17e8bda73de90 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 27 Aug 2022 03:52:32 +0100 Subject: [PATCH 31/57] feat(verification): remove roles on join for non vegan --- src/listeners/verification/joinVC.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 390aa5e..272ed56 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -117,6 +117,15 @@ class VerificationJoinVCListener extends Listener { + 'If you leave this voice channel, you will automatically be given the non-vegan role where you gain access to this server and if you\'d like to verify as a vegan again, you\'d have to contact a Mod, which could be done via ModMail.'); // Adds to the database that the user joined verification await joinVerification(channel.id, member); + + // Remove all roles from the user + await member.roles.remove([ + IDs.roles.vegan.vegan, + IDs.roles.trusted, + IDs.roles.nonvegan.nonvegan, + IDs.roles.nonvegan.convinced, + IDs.roles.nonvegan.vegCurious, + ]); } // Check how many voice channels there are From f89d6c07306a467fee2a46e450a1dc20fea02ca7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sun, 28 Aug 2022 02:42:04 +0100 Subject: [PATCH 32/57] feat(verification): add schedule with verify block --- src/listeners/verification/leaveVC.ts | 15 ++++++-- src/scheduled-tasks/verifyUnblock.ts | 54 +++++++++++++++++++++++++++ src/utils/database/verification.ts | 27 ++++++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 src/scheduled-tasks/verifyUnblock.ts diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 7c67514..8564ebb 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -22,10 +22,10 @@ import type { VoiceState, CategoryChannel, VoiceChannel, TextChannel, } from 'discord.js'; import { maxVCs } from '../../utils/verificationConfig'; -import { getUser } from '../../utils/database/verification'; +import { getUser, checkFinish } from '../../utils/database/verification'; import IDs from '../../utils/ids'; -export class VerificationLeaveVCListener extends Listener { +class VerificationLeaveVCListener extends Listener { public constructor(context: Listener.Context, options: Listener.Options) { super(context, { ...options, @@ -82,9 +82,14 @@ export class VerificationLeaveVCListener extends Listener { */ // Remove verify as vegan and give non vegan role - if (!user.roles.cache.has(IDs.roles.vegan.vegan)) { + if (!await checkFinish(channel.id)) { await user.roles.remove(IDs.roles.verifyingAsVegan); - await user.roles.add(IDs.roles.nonvegan.nonvegan); + await user.roles.add([ + IDs.roles.nonvegan.nonvegan, + IDs.roles.verifyBlock, + ]); + // @ts-ignore + this.container.tasks.create('verifyUnblock', { userId: user.id, guildId: guild.id }, 30000); } } @@ -153,3 +158,5 @@ export class VerificationLeaveVCListener extends Listener { ]); } } + +export default VerificationLeaveVCListener; diff --git a/src/scheduled-tasks/verifyUnblock.ts b/src/scheduled-tasks/verifyUnblock.ts new file mode 100644 index 0000000..351c20e --- /dev/null +++ b/src/scheduled-tasks/verifyUnblock.ts @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; +import IDs from '../utils/ids'; + +export class VerifyUnblock extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, options); + } + + public async run(payload: { userId: string, guildId: string }) { + // Get the guild where the user is in + const guild = this.container.client.guilds.cache.get(payload.guildId); + if (guild === undefined) { + console.error('verifyUnblock: Guild not found!'); + return; + } + + // Find GuildMember for the user + const user = guild.members.cache.get(payload.userId); + if (user === undefined) { + console.error('verifyUnblock: GuildMember not found!'); + return; + } + + // Remove the 'verify block' role + await user.roles.remove(IDs.roles.verifyBlock); + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + verifyUnblock: never; + } +} + +export default VerifyUnblock; diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index e533f92..554c900 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -141,3 +141,30 @@ export async function finishVerification( // Close database connection await prisma.$disconnect(); } + +// Checks if verification was complete +export async function checkFinish(channelId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Get the snowflake of the user verifying + const finish = await prisma.verify.findUnique({ + where: { + id: channelId, + }, + select: { + finishTime: true, + }, + }); + + // Close database connection + await prisma.$disconnect(); + + // Checks if query returned is null + if (finish === null) { + return false; + } + + // Return if a finish time has been set meaning verification is complete + return finish.finishTime !== null; +} From 5a5afbfb02a144cd3434e3befec7aa92078bfca7 Mon Sep 17 00:00:00 2001 From: Anthony Date: Tue, 30 Aug 2022 00:39:47 +0100 Subject: [PATCH 33/57] feat(arabot): add fibonacci sequence --- src/utils/mathsSeries.ts | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/utils/mathsSeries.ts diff --git a/src/utils/mathsSeries.ts b/src/utils/mathsSeries.ts new file mode 100644 index 0000000..2a99459 --- /dev/null +++ b/src/utils/mathsSeries.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +// Created because Stove loves Fibonacci sequences +// A fibonacci sequence where n = 0 => 1 +export function fibonacci(position: number) { + let previous = 0; + let next = 1; + let tempNext; + + for (let i = 0; i < position; i += 1) { + tempNext = next + previous; + previous = next; + next = tempNext; + } + + return next; +} From 35de24399a32c1810eb5f361cf7149f756ae61ce Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 31 Aug 2022 00:40:26 +0100 Subject: [PATCH 34/57] feat(arabot): add extra check if guild/user not in cache --- src/scheduled-tasks/verifyUnblock.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/scheduled-tasks/verifyUnblock.ts b/src/scheduled-tasks/verifyUnblock.ts index 351c20e..5af8534 100644 --- a/src/scheduled-tasks/verifyUnblock.ts +++ b/src/scheduled-tasks/verifyUnblock.ts @@ -27,17 +27,23 @@ export class VerifyUnblock extends ScheduledTask { public async run(payload: { userId: string, guildId: string }) { // Get the guild where the user is in - const guild = this.container.client.guilds.cache.get(payload.guildId); + let guild = this.container.client.guilds.cache.get(payload.guildId); if (guild === undefined) { - console.error('verifyUnblock: Guild not found!'); - return; + guild = await this.container.client.guilds.fetch(payload.guildId); + if (guild === undefined) { + console.error('verifyUnblock: Guild not found!'); + return; + } } // Find GuildMember for the user - const user = guild.members.cache.get(payload.userId); + let user = guild.members.cache.get(payload.userId); if (user === undefined) { - console.error('verifyUnblock: GuildMember not found!'); - return; + user = await guild.members.fetch(payload.userId); + if (user === undefined) { + console.error('verifyUnblock: GuildMember not found!'); + return; + } } // Remove the 'verify block' role From cae9091aa198178781c17a9488511ade2bdb3bad Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 31 Aug 2022 02:51:52 +0100 Subject: [PATCH 35/57] feat(arabot): add fibonacci verification ban lengths --- src/listeners/verification/leaveVC.ts | 15 ++++++++++++--- src/utils/database/verification.ts | 19 +++++++++++++++++++ src/utils/verificationConfig.ts | 4 ++++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 8564ebb..2db6c0c 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -21,8 +21,9 @@ import { container, Listener } from '@sapphire/framework'; import type { VoiceState, CategoryChannel, VoiceChannel, TextChannel, } from 'discord.js'; -import { maxVCs } from '../../utils/verificationConfig'; -import { getUser, checkFinish } from '../../utils/database/verification'; +import { maxVCs, leaveBan } from '../../utils/verificationConfig'; +import { getUser, checkFinish, countIncomplete } from '../../utils/database/verification'; +import { fibonacci } from '../../utils/mathsSeries'; import IDs from '../../utils/ids'; class VerificationLeaveVCListener extends Listener { @@ -88,8 +89,16 @@ class VerificationLeaveVCListener extends Listener { IDs.roles.nonvegan.nonvegan, IDs.roles.verifyBlock, ]); + // Create timeout block for user + // Counts the recent times they have incomplete verifications + const incompleteCount = await countIncomplete(user.id) % (leaveBan + 1); + // Creates the length of the time for the ban + const banLength = fibonacci(incompleteCount) * 10000; // * 3600 commented because development + console.log(incompleteCount); + console.log(fibonacci(incompleteCount)); + // @ts-ignore - this.container.tasks.create('verifyUnblock', { userId: user.id, guildId: guild.id }, 30000); + this.container.tasks.create('verifyUnblock', { userId: user.id, guildId: guild.id }, banLength); } } diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index 554c900..b444424 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -168,3 +168,22 @@ export async function checkFinish(channelId: string) { // Return if a finish time has been set meaning verification is complete return finish.finishTime !== null; } + +// Counts how many times the user has not had a verifier join their VC before leaving +export async function countIncomplete(userId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Count how many times the user has not completed a verification + const incompleteCount = await prisma.verify.count({ + where: { + userId, + finishTime: null, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + return incompleteCount; +} diff --git a/src/utils/verificationConfig.ts b/src/utils/verificationConfig.ts index 1b5a7db..c47e22e 100644 --- a/src/utils/verificationConfig.ts +++ b/src/utils/verificationConfig.ts @@ -17,8 +17,12 @@ along with this program. If not, see . */ +// The maximum amount of verification VCs there can be export const maxVCs = 10; +// The maximum amount of leaving bans before time resets +export const leaveBan = 8; + export const questionInfo = [ { question: 'Welcome to Animal Rights Advocates! How did you find the server?', From a893e13d572655fbd97f8ca0ab59a76814feabdf Mon Sep 17 00:00:00 2001 From: Anthony Date: Wed, 31 Aug 2022 03:12:40 +0100 Subject: [PATCH 36/57] feat(verification): add giving all roles back after leaving vc --- src/listeners/verification/leaveVC.ts | 12 ++++----- src/utils/database/dbExistingUser.ts | 35 ++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 7 deletions(-) diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 2db6c0c..25612d3 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -23,6 +23,7 @@ import type { } from 'discord.js'; import { maxVCs, leaveBan } from '../../utils/verificationConfig'; import { getUser, checkFinish, countIncomplete } from '../../utils/database/verification'; +import { fetchRoles } from '../../utils/database/dbExistingUser'; import { fibonacci } from '../../utils/mathsSeries'; import IDs from '../../utils/ids'; @@ -85,17 +86,16 @@ class VerificationLeaveVCListener extends Listener { // Remove verify as vegan and give non vegan role if (!await checkFinish(channel.id)) { await user.roles.remove(IDs.roles.verifyingAsVegan); - await user.roles.add([ - IDs.roles.nonvegan.nonvegan, - IDs.roles.verifyBlock, - ]); + + // Get roles to give back to the user + const roles = await fetchRoles(user.id); + roles.push(IDs.roles.verifyBlock); + await user.roles.add(roles); // Create timeout block for user // Counts the recent times they have incomplete verifications const incompleteCount = await countIncomplete(user.id) % (leaveBan + 1); // Creates the length of the time for the ban const banLength = fibonacci(incompleteCount) * 10000; // * 3600 commented because development - console.log(incompleteCount); - console.log(fibonacci(incompleteCount)); // @ts-ignore this.container.tasks.create('verifyUnblock', { userId: user.id, guildId: guild.id }, banLength); diff --git a/src/utils/database/dbExistingUser.ts b/src/utils/database/dbExistingUser.ts index b86824b..b0a2831 100644 --- a/src/utils/database/dbExistingUser.ts +++ b/src/utils/database/dbExistingUser.ts @@ -134,19 +134,52 @@ export async function fetchRoles(user: string) { const prisma = new PrismaClient(); // Get the user's roles - const roles = await prisma.user.findUnique({ + const roleQuery = await prisma.user.findUnique({ where: { id: user, }, select: { + vegan: true, trusted: true, + activist: true, plus: true, + notVegan: true, vegCurious: true, + convinced: true, }, }); // Close the database connection await prisma.$disconnect(); + // Assign roles to role snowflakes + const roles = []; + + if (roleQuery === null) { + roles.push(''); + return roles; + } + if (roleQuery.vegan) { + roles.push(IDs.roles.vegan.vegan); + } + if (roleQuery.trusted) { + roles.push(IDs.roles.trusted); + } + if (roleQuery.activist) { + roles.push(IDs.roles.vegan.activist); + } + if (roleQuery.plus) { + roles.push(IDs.roles.vegan.plus); + } + if (roleQuery.notVegan) { + roles.push(IDs.roles.nonvegan.nonvegan); + } + if (roleQuery.vegCurious) { + roles.push(IDs.roles.nonvegan.vegCurious); + } + if (roleQuery.convinced) { + roles.push(IDs.roles.nonvegan.convinced); + } + return roles; } From 0829e7c9963510661eeabddf57e9c586dfcd7c57 Mon Sep 17 00:00:00 2001 From: Anthony Date: Thu, 1 Sep 2022 03:37:28 +0100 Subject: [PATCH 37/57] feat(verification): add information on user in text channel --- src/listeners/verification/joinVC.ts | 59 ++++++++++++++++++++++++--- src/listeners/verification/leaveVC.ts | 16 +++++++- src/utils/formatter.ts | 34 +++++++++++++++ 3 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 src/utils/formatter.ts diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 272ed56..dbba347 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -34,9 +34,11 @@ import { MessageButton, MessageEmbed, } from 'discord.js'; +import { time } from '@discordjs/builders'; import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; import { joinVerification, startVerification, finishVerification } from '../../utils/database/verification'; import { userExists, addExistingUser } from '../../utils/database/dbExistingUser'; +import { rolesToString } from '../../utils/formatter'; import IDs from '../../utils/ids'; class VerificationJoinVCListener extends Listener { @@ -79,6 +81,8 @@ class VerificationJoinVCListener extends Listener { const currentChannel = currentChannelGuild as VoiceChannel; const category = categoryGuild as CategoryChannel; + const roles = rolesToString(member.roles.cache.map((r) => r.id)); + // Checks if a verifier has joined if (channel.members.size === 2) { await newState.channel!.permissionOverwrites.set([ @@ -156,8 +160,12 @@ class VerificationJoinVCListener extends Listener { }); // Send a message that someone wants to be verified - await verificationText.send(`${member.user} wants to be verified in ${channel} - \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`); + const userInfoEmbed = await this.getUserInfo(member, roles); + await verificationText.send({ + content: `${member.user} wants to be verified in ${channel} + \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`, + embeds: [userInfoEmbed], + }); await this.verificationProcess(verificationText, channel.id, member, guild); } @@ -180,10 +188,19 @@ class VerificationJoinVCListener extends Listener { deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], }, { - id: IDs.roles.verifyingAsVegan, + id: IDs.roles.nonvegan.nonvegan, allow: ['VIEW_CHANNEL'], deny: ['CONNECT'], }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + deny: ['CONNECT'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, { id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], @@ -205,9 +222,17 @@ class VerificationJoinVCListener extends Listener { deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], }, { - id: IDs.roles.verifyingAsVegan, + id: IDs.roles.nonvegan.nonvegan, allow: ['VIEW_CHANNEL'], }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, { id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], @@ -223,7 +248,11 @@ class VerificationJoinVCListener extends Listener { deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], }, { - id: IDs.roles.verifyingAsVegan, + id: IDs.roles.nonvegan.nonvegan, + deny: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, deny: ['VIEW_CHANNEL'], }, { @@ -234,6 +263,24 @@ class VerificationJoinVCListener extends Listener { await currentChannel.setUserLimit(0); } + // Creates an embed for information about the user + private async getUserInfo(user: GuildMember, roles: string) { + const joinTime = time(user.joinedAt!); + const registerTime = time(user.user.createdAt); + + const embed = new MessageEmbed() + .setColor(user.displayHexColor) + .setTitle(`Information on ${user.user.username}`) + .setThumbnail(user.user.avatarURL()!) + .addFields( + { name: 'Joined:', value: `${joinTime}`, inline: true }, + { name: 'Created:', value: `${registerTime}`, inline: true }, + { name: 'Roles:', value: roles }, + ); + + return embed; + } + private async verificationProcess( channel: TextChannel, verId: string, @@ -419,7 +466,7 @@ class VerificationJoinVCListener extends Listener { embed = new MessageEmbed() .setColor('#34c000') .setTitle(`Successfully verified ${user.displayName}!`) - .setThumbnail(user.avatarURL()!) + .setThumbnail(user.user.avatarURL()!) .addFields( { name: 'Roles:', value: this.getTextRoles(info.roles) }, ); diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 25612d3..e27661b 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -141,9 +141,17 @@ class VerificationLeaveVCListener extends Listener { deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], }, { - id: IDs.roles.verifyingAsVegan, + id: IDs.roles.nonvegan.nonvegan, allow: ['VIEW_CHANNEL'], }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, { id: IDs.roles.staff.verifier, allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], @@ -161,7 +169,11 @@ class VerificationLeaveVCListener extends Listener { await verification!.permissionOverwrites.set([ { - id: IDs.roles.verifyingAsVegan, + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, allow: ['VIEW_CHANNEL'], }, ]); diff --git a/src/utils/formatter.ts b/src/utils/formatter.ts new file mode 100644 index 0000000..5dc0664 --- /dev/null +++ b/src/utils/formatter.ts @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import type { Snowflake } from 'discord-api-types/globals'; + +export function rolesToString(roles: Snowflake[]) { + let output = ''; + + roles.forEach((role) => { + output += `<@&${role}>`; + }); + + if (output.length === 0) { + output = 'None'; + } + + return output; +} From 915f7d7048edf1b6746945b1ee6a53f9e5a0f792 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 2 Sep 2022 01:20:07 +0100 Subject: [PATCH 38/57] feat(verification): add verification block after verify --- src/listeners/verification/joinVC.ts | 10 ++++++++++ src/listeners/verification/leaveVC.ts | 12 ++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index dbba347..d987b8d 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -462,6 +462,14 @@ class VerificationJoinVCListener extends Listener { await finishVerification(verId, button.user.id, info); // Give roles on Discord await this.giveRoles(user, info.roles); + // Add timeout if they do not have activist role + if (!info.roles.activist) { + // @ts-ignore + this.container.tasks.create('verifyUnblock', { + userId: user.id, + guildId: guild.id, + }, (info.roles.vegan || info.roles.convinced) ? 604800000 : 1814400000); + } // Add embed saying verification completed embed = new MessageEmbed() .setColor('#34c000') @@ -564,6 +572,8 @@ class VerificationJoinVCListener extends Listener { } if (roles.activist) { rolesAdd.push(IDs.roles.vegan.activist); + } else { + rolesAdd.push(IDs.roles.verifyBlock); } if (roles.trusted) { rolesAdd.push(IDs.roles.trusted); diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index e27661b..0675291 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -76,13 +76,6 @@ class VerificationLeaveVCListener extends Listener { console.log(userSnowflake); const user = guild.members.cache.get(userSnowflake!)!; - /* - // Add the user to the database if it's not a verifier meeting - if (!oldState.channel.name.includes(' - Verification')) { - await finishVerification(oldState.channelId!, true, true, false, false); - } - */ - // Remove verify as vegan and give non vegan role if (!await checkFinish(channel.id)) { await user.roles.remove(IDs.roles.verifyingAsVegan); @@ -98,7 +91,10 @@ class VerificationLeaveVCListener extends Listener { const banLength = fibonacci(incompleteCount) * 10000; // * 3600 commented because development // @ts-ignore - this.container.tasks.create('verifyUnblock', { userId: user.id, guildId: guild.id }, banLength); + this.container.tasks.create('verifyUnblock', { + userId: user.id, + guildId: guild.id, + }, banLength); } } From 8ee0b924fafa6236d42a01538b8470700b8d092a Mon Sep 17 00:00:00 2001 From: smyalygames Date: Fri, 23 Sep 2022 18:21:59 +0100 Subject: [PATCH 39/57] refactor(arabot): move db functions to utils --- src/utils/database/sus.ts | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/utils/database/sus.ts diff --git a/src/utils/database/sus.ts b/src/utils/database/sus.ts new file mode 100644 index 0000000..5017868 --- /dev/null +++ b/src/utils/database/sus.ts @@ -0,0 +1,99 @@ +import { PrismaClient } from '@prisma/client'; + +export async function addToDatabase(userId: string, modId: string, message: string) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Add the user to the database + await prisma.sus.create({ + data: { + user: { + connect: { + id: userId, + }, + }, + mod: { + connect: { + id: modId, + }, + }, + note: message, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +// Get a list of sus notes from the user +export async function findNotes(userId: string, active: boolean) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to get the specific user's sus notes + const note = await prisma.sus.findMany({ + where: { + userId, + active, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + return note; +} + +// Get one note from the id +export async function getNote(noteId: number) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to get the specific user's sus notes + const note = await prisma.sus.findUnique({ + where: { + id: noteId, + }, + }); + + // Close the database connection + await prisma.$disconnect(); + return note; +} + +export async function deactivateNote(noteId: number) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to deactivate the specific sus note + await prisma.sus.update({ + where: { + id: noteId, + }, + data: { + active: false, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} + +export async function deactivateAllNotes(userId: string) { + // Initialise the database connection + const prisma = new PrismaClient(); + + // Query to deactivate the specific user's sus notes + await prisma.sus.updateMany({ + where: { + userId: { + contains: userId, + }, + }, + data: { + active: false, + }, + }); + + // Close the database connection + await prisma.$disconnect(); +} From 0749d8158689a70cf0b9c9457b345624f33bdebe Mon Sep 17 00:00:00 2001 From: smyalygames Date: Fri, 23 Sep 2022 18:22:11 +0100 Subject: [PATCH 40/57] refactor(arabot): move db functions to utils --- src/commands/mod/sus.ts | 107 +++------------------------------------- 1 file changed, 7 insertions(+), 100 deletions(-) diff --git a/src/commands/mod/sus.ts b/src/commands/mod/sus.ts index 13f960f..1c24169 100644 --- a/src/commands/mod/sus.ts +++ b/src/commands/mod/sus.ts @@ -21,112 +21,19 @@ import { Command, RegisterBehavior } from '@sapphire/framework'; import { MessageEmbed, MessageActionRow, MessageButton, Constants, ButtonInteraction, } from 'discord.js'; -import { PrismaClient } from '@prisma/client'; import { isMessageInstance } from '@sapphire/discord.js-utilities'; import { addExistingUser, userExists } from '../../utils/database/dbExistingUser'; +import { + addToDatabase, + findNotes, + getNote, + deactivateNote, + deactivateAllNotes, +} from '../../utils/database/sus'; import IDs from '../../utils/ids'; // TODO add a check when they join the server to give the user the sus role again -async function addToDatabase(userId: string, modId: string, message: string) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Add the user to the database - await prisma.sus.create({ - data: { - user: { - connect: { - id: userId, - }, - }, - mod: { - connect: { - id: modId, - }, - }, - note: message, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -// Get a list of sus notes from the user -async function findNotes(userId: string, active: boolean) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to get the specific user's sus notes - const note = await prisma.sus.findMany({ - where: { - userId, - active, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - return note; -} - -// Get one note from the id -async function getNote(noteId: number) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to get the specific user's sus notes - const note = await prisma.sus.findUnique({ - where: { - id: noteId, - }, - }); - - // Close the database connection - await prisma.$disconnect(); - return note; -} - -async function deactivateNote(noteId: number) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to deactivate the specific sus note - await prisma.sus.update({ - where: { - id: noteId, - }, - data: { - active: false, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -async function deactivateAllNotes(userId: string) { - // Initialise the database connection - const prisma = new PrismaClient(); - - // Query to deactivate the specific user's sus notes - await prisma.sus.updateMany({ - where: { - userId: { - contains: userId, - }, - }, - data: { - active: false, - }, - }); - - // Close the database connection - await prisma.$disconnect(); -} - -// Main command class SusCommand extends Command { public constructor(context: Command.Context) { super(context, { From 34dc689f942fb1972acc1eb258c617572453a1f6 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 23 Sep 2022 19:14:45 +0100 Subject: [PATCH 41/57] feat(db): add previous migrations to git --- prisma/migrations/20220806153942_/migration.sql | 14 ++++++++++++++ .../migration.sql | 8 ++++++++ .../20220806193317_verification_time/migration.sql | 10 ++++++++++ .../20220806194157_verification_time/migration.sql | 3 +++ .../20220806202004_change_id/migration.sql | 14 ++++++++++++++ .../20220806203429_verify_date/migration.sql | 2 ++ .../20220826220735_verification_info/migration.sql | 10 ++++++++++ .../20220826221107_add_ver_convinced/migration.sql | 2 ++ 8 files changed, 63 insertions(+) create mode 100644 prisma/migrations/20220806153942_/migration.sql create mode 100644 prisma/migrations/20220806162141_verification_channel/migration.sql create mode 100644 prisma/migrations/20220806193317_verification_time/migration.sql create mode 100644 prisma/migrations/20220806194157_verification_time/migration.sql create mode 100644 prisma/migrations/20220806202004_change_id/migration.sql create mode 100644 prisma/migrations/20220806203429_verify_date/migration.sql create mode 100644 prisma/migrations/20220826220735_verification_info/migration.sql create mode 100644 prisma/migrations/20220826221107_add_ver_convinced/migration.sql diff --git a/prisma/migrations/20220806153942_/migration.sql b/prisma/migrations/20220806153942_/migration.sql new file mode 100644 index 0000000..066741c --- /dev/null +++ b/prisma/migrations/20220806153942_/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - You are about to drop the column `balance` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `lastDaily` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `level` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `xp` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "User" DROP COLUMN "balance", +DROP COLUMN "lastDaily", +DROP COLUMN "level", +DROP COLUMN "xp"; diff --git a/prisma/migrations/20220806162141_verification_channel/migration.sql b/prisma/migrations/20220806162141_verification_channel/migration.sql new file mode 100644 index 0000000..3c49694 --- /dev/null +++ b/prisma/migrations/20220806162141_verification_channel/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - Added the required column `channelId` to the `VerifyUnblock` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "channelId" TEXT NOT NULL; diff --git a/prisma/migrations/20220806193317_verification_time/migration.sql b/prisma/migrations/20220806193317_verification_time/migration.sql new file mode 100644 index 0000000..6ea66f1 --- /dev/null +++ b/prisma/migrations/20220806193317_verification_time/migration.sql @@ -0,0 +1,10 @@ +/* + Warnings: + + - You are about to drop the column `time` on the `VerifyUnblock` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Verify" DROP COLUMN "time", +ADD COLUMN "finishTime" TIMESTAMP(3), +ADD COLUMN "startTime" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP; diff --git a/prisma/migrations/20220806194157_verification_time/migration.sql b/prisma/migrations/20220806194157_verification_time/migration.sql new file mode 100644 index 0000000..576590b --- /dev/null +++ b/prisma/migrations/20220806194157_verification_time/migration.sql @@ -0,0 +1,3 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "joinTime" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ALTER COLUMN "startTime" DROP NOT NULL; diff --git a/prisma/migrations/20220806202004_change_id/migration.sql b/prisma/migrations/20220806202004_change_id/migration.sql new file mode 100644 index 0000000..d4fec5f --- /dev/null +++ b/prisma/migrations/20220806202004_change_id/migration.sql @@ -0,0 +1,14 @@ +/* + Warnings: + + - The primary key for the `VerifyUnblock` table will be changed. If it partially fails, the table could be left without primary key constraint. + - You are about to drop the column `channelId` on the `VerifyUnblock` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE "Verify" DROP CONSTRAINT "Verify_pkey", +DROP COLUMN "channelId", +ALTER COLUMN "id" DROP DEFAULT, +ALTER COLUMN "id" SET DATA TYPE TEXT, +ADD CONSTRAINT "Verify_pkey" PRIMARY KEY ("id"); +DROP SEQUENCE "Verify_id_seq"; diff --git a/prisma/migrations/20220806203429_verify_date/migration.sql b/prisma/migrations/20220806203429_verify_date/migration.sql new file mode 100644 index 0000000..4c82c7e --- /dev/null +++ b/prisma/migrations/20220806203429_verify_date/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Verify" ALTER COLUMN "startTime" DROP DEFAULT; diff --git a/prisma/migrations/20220826220735_verification_info/migration.sql b/prisma/migrations/20220826220735_verification_info/migration.sql new file mode 100644 index 0000000..d613c76 --- /dev/null +++ b/prisma/migrations/20220826220735_verification_info/migration.sql @@ -0,0 +1,10 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "activist" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "food" INTEGER, +ADD COLUMN "length" INTEGER, +ADD COLUMN "life" INTEGER, +ADD COLUMN "reason" INTEGER, +ADD COLUMN "reasoning" INTEGER, +ADD COLUMN "trusted" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "vegCurious" BOOLEAN NOT NULL DEFAULT false, +ADD COLUMN "where" INTEGER; diff --git a/prisma/migrations/20220826221107_add_ver_convinced/migration.sql b/prisma/migrations/20220826221107_add_ver_convinced/migration.sql new file mode 100644 index 0000000..4ae2e1c --- /dev/null +++ b/prisma/migrations/20220826221107_add_ver_convinced/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "convinced" BOOLEAN NOT NULL DEFAULT false; From ee27bb758263cefd7595b66307635139978d1ce6 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Fri, 30 Sep 2022 14:42:59 +0100 Subject: [PATCH 42/57] feat(arabot): add sus notes to verification --- src/listeners/verification/joinVC.ts | 30 +++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index d987b8d..3af5317 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -37,6 +37,7 @@ import { import { time } from '@discordjs/builders'; import { maxVCs, questionInfo, serverFind } from '../../utils/verificationConfig'; import { joinVerification, startVerification, finishVerification } from '../../utils/database/verification'; +import { findNotes } from '../../utils/database/sus'; import { userExists, addExistingUser } from '../../utils/database/dbExistingUser'; import { rolesToString } from '../../utils/formatter'; import IDs from '../../utils/ids'; @@ -161,10 +162,11 @@ class VerificationJoinVCListener extends Listener { // Send a message that someone wants to be verified const userInfoEmbed = await this.getUserInfo(member, roles); + const susNotes = await this.getSus(member, guild); await verificationText.send({ content: `${member.user} wants to be verified in ${channel} \n<@&${IDs.roles.staff.verifier}> <@&${IDs.roles.staff.trialVerifier}>`, - embeds: [userInfoEmbed], + embeds: [userInfoEmbed, susNotes], }); await this.verificationProcess(verificationText, channel.id, member, guild); @@ -281,6 +283,32 @@ class VerificationJoinVCListener extends Listener { return embed; } + // Creates the embed to display the sus note + private async getSus(user: GuildMember, guild: Guild) { + const notes = await findNotes(user.id, true); + + const embed = new MessageEmbed() + .setColor(user.displayHexColor) + .setTitle(`${notes.length} sus notes for ${user.user.username}`); + + // Add up to 10 of the latest sus notes to the embed + for (let i = notes.length > 10 ? notes.length - 10 : 0; i < notes.length; i += 1) { + // Get mod name + const modGuildMember = guild!.members.cache.get(notes[i].modId); + let mod = notes[i].modId; + if (modGuildMember !== undefined) { + mod = modGuildMember!.displayName; + } + // Add sus note to embed + embed.addFields({ + name: `Sus ID: ${notes[i].id} | Moderator: ${mod} | Date: `, + value: notes[i].note, + }); + } + + return embed; + } + private async verificationProcess( channel: TextChannel, verId: string, From 70854915af53a7164198409e98da50486cede6c4 Mon Sep 17 00:00:00 2001 From: Anthony Date: Fri, 14 Oct 2022 11:11:05 +0100 Subject: [PATCH 43/57] feat(verification): add 15 minute timeout logic --- src/listeners/verification/joinVC.ts | 7 ++++ src/scheduled-tasks/verifyTimeout.ts | 56 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/scheduled-tasks/verifyTimeout.ts diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 3af5317..556f310 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -131,6 +131,13 @@ class VerificationJoinVCListener extends Listener { IDs.roles.nonvegan.convinced, IDs.roles.nonvegan.vegCurious, ]); + + // Start 15-minute timer if verifier does not join + // @ts-ignore + this.container.tasks.create('verifyTimeout', { + userId: member.id, + guildId: guild.id, + }, 30_000); } // Check how many voice channels there are diff --git a/src/scheduled-tasks/verifyTimeout.ts b/src/scheduled-tasks/verifyTimeout.ts new file mode 100644 index 0000000..47a0a9d --- /dev/null +++ b/src/scheduled-tasks/verifyTimeout.ts @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import type { VoiceChannel } from 'discord.js'; +import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; + +export class VerifyTimeout extends ScheduledTask { + public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { + super(context, options); + } + + public async run(payload: { channelId: string, userId: string }) { + // Get the guild where the user is in + let channel = this.container.client.channels.cache.get(payload.channelId) as VoiceChannel | undefined; + if (channel === undefined) { + channel = await this.container.client.channels.fetch(payload.channelId) as VoiceChannel | undefined; + if (channel === undefined) { + console.error('verifyTimeout: Channel not found!'); + return; + } + } + + if (channel.members.size < 2 && channel.members.has(payload.userId)) { + const user = channel.members.get(payload.userId); + if (user === undefined) { + console.error('verifyTimeout: GuildMember not found!'); + return; + } + await user.voice.disconnect(); + } + } +} + +declare module '@sapphire/plugin-scheduled-tasks' { + interface ScheduledTasks { + verifyUnblock: never; + } +} + +export default VerifyTimeout; From bb19a1752293bbd119cc0cb5a80c7cd2db91c9c5 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Fri, 14 Oct 2022 18:11:52 +0100 Subject: [PATCH 44/57] fix(arabot): wrong variables in payload --- src/listeners/verification/joinVC.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 556f310..000a0b4 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -135,8 +135,8 @@ class VerificationJoinVCListener extends Listener { // Start 15-minute timer if verifier does not join // @ts-ignore this.container.tasks.create('verifyTimeout', { + channelId: channel.id, userId: member.id, - guildId: guild.id, }, 30_000); } From 24afe3c4b2e5b6d4bcfbb06eb1a1c3cef2440ca3 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Sun, 16 Oct 2022 16:08:51 +0100 Subject: [PATCH 45/57] feat(verify): add checks on startup --- src/listeners/verification/joinVC.ts | 4 +- src/listeners/verification/leaveVC.ts | 3 +- src/listeners/verification/start.ts | 111 ++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 src/listeners/verification/start.ts diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 000a0b4..0dd6c36 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -137,7 +137,7 @@ class VerificationJoinVCListener extends Listener { this.container.tasks.create('verifyTimeout', { channelId: channel.id, userId: member.id, - }, 30_000); + }, 30_000); // TODO change before production to 15 mins } // Check how many voice channels there are @@ -148,7 +148,7 @@ class VerificationJoinVCListener extends Listener { if (!verifier) { const verificationText = await guild.channels.create(`✅┃${member.displayName}-verification`, { type: 'GUILD_TEXT', - topic: `Channel for verifiers only. ${member.id} (Please do not change this)`, + topic: `Channel for verifiers only. ${member.id} ${channel.id} (Please do not change this)`, parent: category.id, userLimit: 1, permissionOverwrites: [ diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 0675291..392f34e 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -73,7 +73,6 @@ class VerificationLeaveVCListener extends Listener { // Allow more people to join VC if there are less than 10 VCs if (!verifier) { - console.log(userSnowflake); const user = guild.members.cache.get(userSnowflake!)!; // Remove verify as vegan and give non vegan role @@ -88,7 +87,7 @@ class VerificationLeaveVCListener extends Listener { // Counts the recent times they have incomplete verifications const incompleteCount = await countIncomplete(user.id) % (leaveBan + 1); // Creates the length of the time for the ban - const banLength = fibonacci(incompleteCount) * 10000; // * 3600 commented because development + const banLength = fibonacci(incompleteCount) * 10000; // TODO * 3600 commented because development // @ts-ignore this.container.tasks.create('verifyUnblock', { diff --git a/src/listeners/verification/start.ts b/src/listeners/verification/start.ts new file mode 100644 index 0000000..2410702 --- /dev/null +++ b/src/listeners/verification/start.ts @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { Listener } from '@sapphire/framework'; +import type { + Client, + CategoryChannel, + TextChannel, + VoiceChannel, +} from 'discord.js'; +import IDs from '../../utils/ids'; + +class VerificationReady extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + once: true, + event: 'ready', + }); + } + + public async run(client: Client) { + // Get verification category + let category = client.channels.cache.get(IDs.categories.verification) as CategoryChannel | undefined; + if (category === undefined) { + category = await client.channels.fetch(IDs.categories.verification) as CategoryChannel | undefined; + if (category === undefined) { + console.error('verifyStart: Channel not found'); + return; + } + } + + // Check how many voice channels there are + let voiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + const emptyVC: string[] = []; + // Delete voice channels + voiceChannels.forEach((c) => { + const voiceChannel = c as VoiceChannel; + if (voiceChannel.members.size === 0) { + emptyVC.push(voiceChannel.id); + voiceChannel.delete(); + } + }); + + // Delete text channels + const textChannels = category.children.filter((c) => c.type === 'GUILD_TEXT'); + textChannels.forEach((c) => { + const textChannel = c as TextChannel; + // Checks if the channel topic has the user's snowflake + emptyVC.forEach((snowflake) => { + if (textChannel.topic!.includes(snowflake)) { + textChannel.delete(); + } + }); + }); + + // Check if there is no voice channels, create verification + voiceChannels = category.children.filter((c) => c.type === 'GUILD_VOICE'); + if (voiceChannels.size === emptyVC.length) { + await category.guild.channels.create('Verification', { + type: 'GUILD_VOICE', + parent: IDs.categories.verification, + userLimit: 1, + permissionOverwrites: [ + { + id: category.guild.roles.everyone, + deny: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + { + id: IDs.roles.verifyBlock, + deny: ['VIEW_CHANNEL', 'CONNECT', 'SEND_MESSAGES'], + }, + { + id: IDs.roles.nonvegan.nonvegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.vegan, + allow: ['VIEW_CHANNEL'], + }, + { + id: IDs.roles.vegan.activist, + deny: ['VIEW_CHANNEL', 'CONNECT'], + }, + { + id: IDs.roles.staff.verifier, + allow: ['SEND_MESSAGES', 'VIEW_CHANNEL'], + }, + ], + }); + } + } +} + +export default VerificationReady; From 1993682484b5aa2ff7c9ae8ed97a6aa7c561dd3e Mon Sep 17 00:00:00 2001 From: smyalygames Date: Sun, 16 Oct 2022 22:05:46 +0100 Subject: [PATCH 46/57] build(config): update packages --- Dockerfile | 2 + package-lock.json | 1032 +++++++++++++++++++++++++-------------------- package.json | 3 +- 3 files changed, 571 insertions(+), 466 deletions(-) diff --git a/Dockerfile b/Dockerfile index c6003ff..add3992 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,6 +11,8 @@ RUN npm install COPY . . +RUN npx prisma generate + RUN npm run build RUN chown node:node /opt/app/ diff --git a/package-lock.json b/package-lock.json index f45f4db..9a29a98 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.0.1", "license": "GPL-3.0-or-later", "dependencies": { + "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", "@sapphire/framework": "^3.0.0", @@ -33,7 +34,7 @@ "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-plugin-import": "^2.26.0", - "prisma": "^4.2.1" + "prisma": "^4.4.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -48,13 +49,13 @@ } }, "node_modules/@discordjs/builders": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", - "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", - "deprecated": "no longer supported", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.3.0.tgz", + "integrity": "sha512-Pvca6Nw8Hp+n3N+Wp17xjygXmMvggbh5ywUsOYE2Et4xkwwVRwgzxDJiMUuYapPtnYt4w/8aKlf5khc8ipLvhg==", "dependencies": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.0", + "discord-api-types": "^0.37.12", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.1", "tslib": "^2.4.0" @@ -64,27 +65,35 @@ } }, "node_modules/@discordjs/builders/node_modules/discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + "version": "0.37.14", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.14.tgz", + "integrity": "sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==" }, "node_modules/@discordjs/collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.1.tgz", - "integrity": "sha512-5V/wswzR3r2RVYXLxxg4TvrAnBhVCNgHTXhC+OUtLoriJ072rPMHo+Iw1SS1vrCckp8Es40XM411+WkNRPaXFw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.2.0.tgz", + "integrity": "sha512-VvrrtGb7vbfPHzbhGq9qZB5o8FOB+kfazrxdt0OtxzSkoBuw9dURMkCwWizZ00+rDpiK2HmLHBZX+y6JsG9khw==", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==", "engines": { "node": ">=16.9.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -94,12 +103,15 @@ }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -110,11 +122,14 @@ "node": ">=10.10.0" } }, - "node_modules/@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "engines": { + "node": ">=12.22" + }, "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" @@ -261,12 +276,12 @@ } }, "node_modules/@prisma/client": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.2.1.tgz", - "integrity": "sha512-PZBkY60+k5oix+e6IUfl3ub8TbRLNsPLdfWrdy2eh80WcHTaT+/UfvXf/B7gXedH7FRtbPFHZXk1hZenJiJZFQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" }, "engines": { "node": ">=14.17" @@ -281,16 +296,16 @@ } }, "node_modules/@prisma/engines": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", - "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826.tgz", - "integrity": "sha512-tktkqdiwqE4QhmE088boPt+FwPj1Jub/zk+5F6sEfcRHzO5yz9jyMD5HFVtiwxZPLx/8Xg9ElnuTi8E5lWVQFQ==" + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", @@ -311,13 +326,13 @@ } }, "node_modules/@sapphire/discord.js-utilities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.0.0.tgz", - "integrity": "sha512-XvXkL0/e4AwKIipSxPeNNa8UPmSCoc+vwkNrnvV43a0JUJ1acxPPWrcpxAzE9lRxPY/vDLYaaEw7M/hkg3i5xQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.1.1.tgz", + "integrity": "sha512-xWiduo2kYXMJ2IHKYjPGzL6VisTP/kwVh61BlxBbnPOKQ87F3EYe4WuXuX7JqoPUZVdRSG3ZuBgrz0mKGF4p3w==", "dependencies": { "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/time-utilities": "^1.7.6", - "@sapphire/utilities": "^3.9.2", + "@sapphire/duration": "^1.0.0", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" }, "engines": { @@ -325,22 +340,29 @@ "npm": ">=7.0.0" } }, + "node_modules/@sapphire/duration": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/duration/-/duration-1.0.0.tgz", + "integrity": "sha512-B+6nKYnBmIlqqbamcR4iBvbQHz6/Kq2JUVM0rA3lQ+aYUYDdcA1Spt66CKtPWwdTYEtSv0VY6Jv27WCtFNYTUg==", + "engines": { + "node": ">=v14.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@sapphire/framework": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0.tgz", - "integrity": "sha512-VflLMOHKtecTxAi2N1m1DzCN/qKB7vrRolx9UFXmcQg9fGmYzj9yaKM3Fyw+ZvhpS/gijGWN1lWSr8fyTscdEA==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.3.tgz", + "integrity": "sha512-YHB6oeY095vrRv8ksW0zm/GSWuw+vDLvU0BzJBTGI0KYQfNq2d6OVCjY0ADxFgQSgC9AxOHj2h2GvGcLET+S4g==", "dependencies": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/lexure": "^1.0.1", - "@sapphire/pieces": "^3.5.1", - "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^2.4.0", - "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.9.2", - "@types/object-hash": "^2.2.1", - "object-hash": "^3.0.0", + "@sapphire/discord.js-utilities": "^5.0.1", + "@sapphire/lexure": "^1.1.1", + "@sapphire/pieces": "^3.5.2", + "@sapphire/ratelimits": "^2.4.5", + "@sapphire/result": "^2.5.0", + "@sapphire/stopwatch": "^1.5.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" }, "engines": { @@ -348,12 +370,33 @@ "npm": ">=7.0.0" } }, - "node_modules/@sapphire/lexure": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.1.tgz", - "integrity": "sha512-bxI85SqPERicAC8fyZNRjrK2SroXFtpa/vgUNExH8VSM1LIysZE6zDRGCvllAfOdEVGSGBKjNRLfT9kYwNDhXg==", + "node_modules/@sapphire/framework/node_modules/@discordjs/builders": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", + "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "deprecated": "no longer supported", "dependencies": { - "@sapphire/result": "^2.1.1" + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.2", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/@sapphire/framework/node_modules/discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + }, + "node_modules/@sapphire/lexure": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.1.2.tgz", + "integrity": "sha512-+v3P3EMDdFoybHH7c7cMcz30jEyxujkxWu5f958cf/Sm27fMM0IqwILnNFUpExZCBAueEM/eoSgbRl4q+K+0jg==", + "dependencies": { + "@sapphire/result": "^2.6.0" }, "engines": { "node": ">=v14.0.0", @@ -361,12 +404,12 @@ } }, "node_modules/@sapphire/pieces": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.1.tgz", - "integrity": "sha512-GEm7W6hAMC1yN76z0SZlIij66MDcuvWf7ra2TPGhflmv5ZUG4vNHNMktexP4AwEgKeF1jKJouVrIs3lAC3e4ZQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.2.tgz", + "integrity": "sha512-B8ghwre5naTIMnJIlqJGhKX6ZTpGqz4oAtBd/ihX0CY69cPtbem3VHfZ8Sf5C+50l3mfe2AU7CfZQn9kLQR2fQ==", "dependencies": { - "@discordjs/collection": "^1.0.1", - "@sapphire/utilities": "^3.9.2", + "@discordjs/collection": "^1.1.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" }, "engines": { @@ -375,11 +418,12 @@ } }, "node_modules/@sapphire/plugin-scheduled-tasks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0.tgz", - "integrity": "sha512-MIYiG40HW9kPeZGPcGlLX3uPkKaruG2GIkUhu5gNS1kJogtx6NdZlY5hKBDnpjl1jND5+d2gX9aaLNFA7+UxKA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.1.tgz", + "integrity": "sha512-vLxfHBu2vKaJZ9v2f4z+VDZaPeDqS8bm+Sc2minRwJPw1hWAHiPqmxCBPIONY7eOQ9qKayvhKYTIwwruxgO/Mg==", "dependencies": { - "@sapphire/time-utilities": "^1.7.6", + "@sapphire/stopwatch": "^1.4.1", + "@sapphire/utilities": "^3.9.3", "tslib": "^2.4.0" }, "engines": { @@ -388,11 +432,11 @@ } }, "node_modules/@sapphire/plugin-subcommands": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.0.0.tgz", - "integrity": "sha512-OLNAIQGEtViG6gYZ5G3/m/Um/mmpH3z7PGRCDv/k7nls9FSvD4Ap7TpeyXFupRI1gT2NJGKOE4TuaHjPwD0k2Q==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.3.tgz", + "integrity": "sha512-xUDkHdOXmqquO++I54ZOZg8Prh2YIJ7sSGBLXCU+FiNDbsfzbxr/McCfnKL65L6RBYOjf8d06up3GKPL8t9GpQ==", "dependencies": { - "@sapphire/utilities": "^3.9.2", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" }, "engines": { @@ -401,11 +445,11 @@ } }, "node_modules/@sapphire/ratelimits": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.4.tgz", - "integrity": "sha512-9gZ1BaY99HLWOcfuhlu0WklirHhVc6QD1pm5/v2W0O9pBpMHrd1GImVMXjYZRoy1qpmE2ZggSmN1665lktTCMw==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.5.tgz", + "integrity": "sha512-2wqpVPRaPUE+CWStLm6wGLj1uA4Ln/9qbH4Ue/eCHC6/R5lJz0+8nGD1LpiYOcyeVLTHbmwODGeD92obkPej2g==", "dependencies": { - "@sapphire/time-utilities": "^1.7.4" + "@sapphire/timer-manager": "^1.0.0" }, "engines": { "node": ">=v14.0.0", @@ -413,18 +457,18 @@ } }, "node_modules/@sapphire/result": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.4.0.tgz", - "integrity": "sha512-BJkBsXYjTr6nQmKQnUriA1IyQrVDd7rKHTnbk2n03d/sri9ZFYYCRZ8wfFv+Z8QUasFWliypg3Qstz29G1nnjQ==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.0.tgz", + "integrity": "sha512-gdW6n/oDZ8aC1439Ub3RiLQ6L4VHAxbN0AhGJWNkEZ6Z6Ww2V62fwRiA/73OPfgYQKXk9ljhAFiqNO91KAonHQ==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, "node_modules/@sapphire/shapeshift": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", - "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.7.0.tgz", + "integrity": "sha512-A6vI1zJoxhjWo4grsxpBRBgk96SqSdjLX5WlzKp9H+bJbkM07mvwcbtbVAmUZHbi/OG3HLfiZ1rlw4BhH6tsBQ==", "dependencies": { "fast-deep-equal": "^3.1.3", "lodash.uniqwith": "^4.5.0" @@ -435,24 +479,21 @@ } }, "node_modules/@sapphire/stopwatch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.4.1.tgz", - "integrity": "sha512-FoZIM7oQ1kwkjWpl/rKReuDFSlkCDjDp//1Np2mmQD+xQ2Zyo/J2MaYAITprwQr3AUBu/OOUJvqm7f8lA9R7gA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.5.0.tgz", + "integrity": "sha512-DtyKugdy3JTqm6JnEepTY64fGJAqlusDVrlrzifEgSCfGYCqpvB+SBldkWtDH+z+zLcp+PyaFLq7xpVfkhmvGg==", "dependencies": { - "tslib": "^2.3.1" + "tslib": "^2.4.0" }, "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" } }, - "node_modules/@sapphire/time-utilities": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@sapphire/time-utilities/-/time-utilities-1.7.6.tgz", - "integrity": "sha512-VsMVYFmS9Iu0buPs7gwn1D6vqIC04ezVMBRIo8vRTB2s7UNN/vQReX2cLABFoDVqs7RHQsvr2DPoTWHEDYw9YA==", - "dependencies": { - "@sapphire/utilities": "^3.9.2" - }, + "node_modules/@sapphire/timer-manager": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/timer-manager/-/timer-manager-1.0.0.tgz", + "integrity": "sha512-vxxnv75QPMGKt6IB6nL2xRJfwzcUQ9DBGzJLg6G8eS5O4u7j3IR/yr/GQsa4gIpjw6kQOgn8lUdnSTlpnERTbQ==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -473,9 +514,9 @@ } }, "node_modules/@sapphire/utilities": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.2.tgz", - "integrity": "sha512-CG8mFPse+VDUVenj3PqZyh9PATFd/pzrQaX2gZqv0f7AzGnlyfm/ygh0tnQRVKpMDFr39uCQqVse8i0f51DAkg==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.11.0.tgz", + "integrity": "sha512-ich7J+329UTEgWxgk8b871rMhbFW/hvXdabdiKaUKd6g10eIMkIakWf+EGkDQsiDSiebIXll9TIPPmWtN3cVSw==", "engines": { "node": ">=v14.0.0", "npm": ">=7.0.0" @@ -523,9 +564,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.7.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.8.tgz", - "integrity": "sha512-/YP55EMK2341JkODUb8DM9O0x1SIz2aBvyF33Uf1c76St3VpsMXEIW0nxuKkq/5cxnbz0RD9cfwNZHEAZQD3ag==" + "version": "18.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", + "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -549,11 +590,6 @@ "node": ">= 6" } }, - "node_modules/@types/object-hash": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-2.2.1.tgz", - "integrity": "sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ==" - }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -563,16 +599,15 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.1.tgz", - "integrity": "sha512-S1iZIxrTvKkU3+m63YUOxYPKaP+yWDQrdhxTglVDVEVBf+aCSw85+BmJnyUaQQsk5TXFG/LpBu9fa+LrAQ91fQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.0.tgz", + "integrity": "sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/type-utils": "5.33.1", - "@typescript-eslint/utils": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/type-utils": "5.40.0", + "@typescript-eslint/utils": "5.40.0", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", "regexpp": "^3.2.0", "semver": "^7.3.7", @@ -596,14 +631,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.1.tgz", - "integrity": "sha512-IgLLtW7FOzoDlmaMoXdxG8HOCByTBXrB1V2ZQYSEV1ggMmJfAkMWTwUjjzagS6OkfpySyhKFkBw7A9jYmcHpZA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", + "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/typescript-estree": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "debug": "^4.3.4" }, "engines": { @@ -623,13 +658,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.1.tgz", - "integrity": "sha512-8ibcZSqy4c5m69QpzJn8XQq9NnqAToC8OdH/W6IXPXv83vRyEDPYLdjAlUx8h/rbusq6MkW4YdQzURGOqsn3CA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", + "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/visitor-keys": "5.33.1" + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -640,12 +675,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.1.tgz", - "integrity": "sha512-X3pGsJsD8OiqhNa5fim41YtlnyiWMF/eKsEZGsHID2HcDqeSC5yr/uLOeph8rNF2/utwuI0IQoAK3fpoxcLl2g==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.0.tgz", + "integrity": "sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.33.1", + "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/utils": "5.40.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -666,9 +702,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.1.tgz", - "integrity": "sha512-7K6MoQPQh6WVEkMrMW5QOA5FO+BOwzHSNd0j3+BlBwd6vtzfZceJ8xJ7Um2XDi/O3umS8/qDX6jdy2i7CijkwQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", + "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -679,13 +715,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.1.tgz", - "integrity": "sha512-JOAzJ4pJ+tHzA2pgsWQi4804XisPHOtbvwUyqsuuq8+y5B5GMZs7lI1xDWs6V2d7gE/Ez5bTGojSK12+IIPtXA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", + "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/visitor-keys": "5.33.1", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -706,17 +742,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.1.tgz", - "integrity": "sha512-uphZjkMaZ4fE8CR4dU7BquOV6u0doeQAr8n6cQenl/poMaIyJtBu8eys5uk6u5HiDH01Mj5lzbJ5SfeDz7oqMQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.0.tgz", + "integrity": "sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/typescript-estree": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -730,12 +767,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.1.tgz", - "integrity": "sha512-nwIxOK8Z2MPWltLKMLOEZwmfBZReqUdbEoHQXeCpa+sRVARe5twpJGHCB4dk9903Yaf0nMAlGbQfaAH92F60eg==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", + "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.33.1", + "@typescript-eslint/types": "5.40.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -904,9 +941,9 @@ } }, "node_modules/bullmq": { - "version": "1.89.1", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.89.1.tgz", - "integrity": "sha512-VpNFa1buQYDOl4yUF0PxVoCDbh/GT/JeQiaWu/8IdPVMk91RToWtsXvaZdVrfp9VAOtP+F1KJr/pFn+ewY2rnw==", + "version": "1.91.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.91.1.tgz", + "integrity": "sha512-u7dat9I8ZwouZ651AMZkBSvB6NVUPpnAjd4iokd9DM41whqIBnDjuL11h7+kEjcpiDKj6E+wxZiER00FqirZQg==", "dependencies": { "cron-parser": "^4.6.0", "get-port": "6.1.2", @@ -916,7 +953,7 @@ "msgpackr": "^1.6.2", "semver": "^7.3.7", "tslib": "^2.0.0", - "uuid": "^8.3.2" + "uuid": "^9.0.0" } }, "node_modules/call-bind": { @@ -958,9 +995,9 @@ } }, "node_modules/cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==", "engines": { "node": ">=0.10.0" } @@ -1116,25 +1153,46 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "node_modules/discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.12.0.tgz", + "integrity": "sha512-K5qhREsYcTHkEqt7+7LcSoXTeQYZpI+SQRs9ei/FhbhUpirmjqFtN99P8W2mrKUyhhy7WXWm7rnna0AooKtIpw==", "dependencies": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", + "discord-api-types": "^0.33.5", "form-data": "^4.0.0", "node-fetch": "^2.6.7", - "ws": "^8.8.1" + "ws": "^8.9.0" }, "engines": { "node": ">=16.6.0", "npm": ">=7.0.0" } }, + "node_modules/discord.js/node_modules/@discordjs/builders": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", + "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "deprecated": "no longer supported", + "dependencies": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.2", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/discord.js/node_modules/@discordjs/builders/node_modules/discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + }, "node_modules/discord.js/node_modules/@discordjs/collection": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz", @@ -1157,39 +1215,40 @@ } }, "node_modules/dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==", "engines": { "node": ">=12" } }, "node_modules/es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -1240,14 +1299,14 @@ } }, "node_modules/eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", + "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1257,13 +1316,12 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -1272,6 +1330,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -1282,8 +1341,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" @@ -1509,9 +1567,9 @@ } }, "node_modules/espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", "dev": true, "dependencies": { "acorn": "^8.8.0", @@ -1591,9 +1649,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1740,12 +1798,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "node_modules/functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -1756,9 +1808,9 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "dependencies": { "function-bind": "^1.1.1", @@ -2018,9 +2070,9 @@ } }, "node_modules/ioredis": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.2.tgz", - "integrity": "sha512-wryKc1ur8PcCmNwfcGkw5evouzpbDXxxkMkzPK8wl4xQfQf7lHe11Jotell5ikMVAtikXJEu/OJVaoV51BggRQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.3.tgz", + "integrity": "sha512-gQNcMF23/NpvjCaa1b5YycUyQJ9rBNH2xP94LWinNpodMWVUPP5Ai/xXANn/SM7gfIvI62B5CCvZxhg5pOgyMw==", "dependencies": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", @@ -2069,9 +2121,9 @@ } }, "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, "engines": { "node": ">= 0.4" @@ -2240,6 +2292,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2342,9 +2400,9 @@ } }, "node_modules/luxon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz", - "integrity": "sha512-hF3kv0e5gwHQZKz4wtm4c+inDtyc7elkanAsBq+fundaCdUBNJB1dHEGUZIM6SfSBUlbVFduPwEtNjFK8wLtcw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==", "engines": { "node": ">=12" } @@ -2408,10 +2466,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/ms": { "version": "2.1.2", @@ -2419,11 +2480,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/msgpackr": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", - "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz", + "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==", "optionalDependencies": { - "msgpackr-extract": "^2.0.2" + "msgpackr-extract": "^2.1.2" } }, "node_modules/msgpackr-extract": { @@ -2483,14 +2544,6 @@ "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -2689,13 +2742,13 @@ } }, "node_modules/prisma": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", - "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "4.2.1" + "@prisma/engines": "4.4.0" }, "bin": { "prisma": "build/index.js", @@ -2876,10 +2929,24 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3157,9 +3224,9 @@ } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3193,19 +3260,13 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -3271,9 +3332,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "engines": { "node": ">=10.0.0" }, @@ -3326,38 +3387,44 @@ } }, "@discordjs/builders": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", - "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.3.0.tgz", + "integrity": "sha512-Pvca6Nw8Hp+n3N+Wp17xjygXmMvggbh5ywUsOYE2Et4xkwwVRwgzxDJiMUuYapPtnYt4w/8aKlf5khc8ipLvhg==", "requires": { - "@sapphire/shapeshift": "^3.5.1", - "discord-api-types": "^0.36.2", + "@discordjs/util": "^0.1.0", + "@sapphire/shapeshift": "^3.7.0", + "discord-api-types": "^0.37.12", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.1", "tslib": "^2.4.0" }, "dependencies": { "discord-api-types": { - "version": "0.36.3", - "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", - "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + "version": "0.37.14", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.37.14.tgz", + "integrity": "sha512-byBH7SfDCMJwxdqeS8k5sihltH88/YPhuwx+vF2cftSxFLdxyHyU/ZxDL3bq+LB2c4ls/TymE76/ISlLfniUXg==" } } }, "@discordjs/collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.0.1.tgz", - "integrity": "sha512-5V/wswzR3r2RVYXLxxg4TvrAnBhVCNgHTXhC+OUtLoriJ072rPMHo+Iw1SS1vrCckp8Es40XM411+WkNRPaXFw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-1.2.0.tgz", + "integrity": "sha512-VvrrtGb7vbfPHzbhGq9qZB5o8FOB+kfazrxdt0OtxzSkoBuw9dURMkCwWizZ00+rDpiK2HmLHBZX+y6JsG9khw==" + }, + "@discordjs/util": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@discordjs/util/-/util-0.1.0.tgz", + "integrity": "sha512-e7d+PaTLVQav6rOc2tojh2y6FE8S7REkqLldq1XF4soCx74XB/DIjbVbVLtBemf0nLW77ntz0v+o5DytKwFNLQ==" }, "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -3367,9 +3434,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", - "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", + "version": "0.10.7", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.7.tgz", + "integrity": "sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -3377,10 +3444,10 @@ "minimatch": "^3.0.4" } }, - "@humanwhocodes/gitignore-to-minimatch": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", - "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true }, "@humanwhocodes/object-schema": { @@ -3476,23 +3543,23 @@ } }, "@prisma/client": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.2.1.tgz", - "integrity": "sha512-PZBkY60+k5oix+e6IUfl3ub8TbRLNsPLdfWrdy2eh80WcHTaT+/UfvXf/B7gXedH7FRtbPFHZXk1hZenJiJZFQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", "requires": { - "@prisma/engines-version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826" + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" } }, "@prisma/engines": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.2.1.tgz", - "integrity": "sha512-0KqBwREUOjBiHwITsQzw2DWfLHjntvbqzGRawj4sBMnIiL5CXwyDUKeHOwXzKMtNr1rEjxEsypM14g0CzLRK3g==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", "devOptional": true }, "@prisma/engines-version": { - "version": "4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.2.0-33.2920a97877e12e055c1333079b8d19cee7f33826.tgz", - "integrity": "sha512-tktkqdiwqE4QhmE088boPt+FwPj1Jub/zk+5F6sEfcRHzO5yz9jyMD5HFVtiwxZPLx/8Xg9ElnuTi8E5lWVQFQ==" + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" }, "@sapphire/async-queue": { "version": "1.5.0", @@ -3505,108 +3572,128 @@ "integrity": "sha512-oFZYl7Prtqy8nD3ymmMpSMRy9Sdhp8E5PSI8n3OoBkHr4eSBvoOcBTxKapvRkHWes+amWeH/uB4UH31x7mG0KQ==" }, "@sapphire/discord.js-utilities": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.0.0.tgz", - "integrity": "sha512-XvXkL0/e4AwKIipSxPeNNa8UPmSCoc+vwkNrnvV43a0JUJ1acxPPWrcpxAzE9lRxPY/vDLYaaEw7M/hkg3i5xQ==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@sapphire/discord.js-utilities/-/discord.js-utilities-5.1.1.tgz", + "integrity": "sha512-xWiduo2kYXMJ2IHKYjPGzL6VisTP/kwVh61BlxBbnPOKQ87F3EYe4WuXuX7JqoPUZVdRSG3ZuBgrz0mKGF4p3w==", "requires": { "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/time-utilities": "^1.7.6", - "@sapphire/utilities": "^3.9.2", + "@sapphire/duration": "^1.0.0", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" } }, + "@sapphire/duration": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/duration/-/duration-1.0.0.tgz", + "integrity": "sha512-B+6nKYnBmIlqqbamcR4iBvbQHz6/Kq2JUVM0rA3lQ+aYUYDdcA1Spt66CKtPWwdTYEtSv0VY6Jv27WCtFNYTUg==" + }, "@sapphire/framework": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.0.0.tgz", - "integrity": "sha512-VflLMOHKtecTxAi2N1m1DzCN/qKB7vrRolx9UFXmcQg9fGmYzj9yaKM3Fyw+ZvhpS/gijGWN1lWSr8fyTscdEA==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@sapphire/framework/-/framework-3.1.3.tgz", + "integrity": "sha512-YHB6oeY095vrRv8ksW0zm/GSWuw+vDLvU0BzJBTGI0KYQfNq2d6OVCjY0ADxFgQSgC9AxOHj2h2GvGcLET+S4g==", "requires": { "@discordjs/builders": "^0.16.0", "@sapphire/discord-utilities": "^2.11.6", - "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/lexure": "^1.0.1", - "@sapphire/pieces": "^3.5.1", - "@sapphire/ratelimits": "^2.4.4", - "@sapphire/result": "^2.4.0", - "@sapphire/stopwatch": "^1.4.1", - "@sapphire/utilities": "^3.9.2", - "@types/object-hash": "^2.2.1", - "object-hash": "^3.0.0", + "@sapphire/discord.js-utilities": "^5.0.1", + "@sapphire/lexure": "^1.1.1", + "@sapphire/pieces": "^3.5.2", + "@sapphire/ratelimits": "^2.4.5", + "@sapphire/result": "^2.5.0", + "@sapphire/stopwatch": "^1.5.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" + }, + "dependencies": { + "@discordjs/builders": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", + "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "requires": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.2", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + } + }, + "discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + } } }, "@sapphire/lexure": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.0.1.tgz", - "integrity": "sha512-bxI85SqPERicAC8fyZNRjrK2SroXFtpa/vgUNExH8VSM1LIysZE6zDRGCvllAfOdEVGSGBKjNRLfT9kYwNDhXg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@sapphire/lexure/-/lexure-1.1.2.tgz", + "integrity": "sha512-+v3P3EMDdFoybHH7c7cMcz30jEyxujkxWu5f958cf/Sm27fMM0IqwILnNFUpExZCBAueEM/eoSgbRl4q+K+0jg==", "requires": { - "@sapphire/result": "^2.1.1" + "@sapphire/result": "^2.6.0" } }, "@sapphire/pieces": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.1.tgz", - "integrity": "sha512-GEm7W6hAMC1yN76z0SZlIij66MDcuvWf7ra2TPGhflmv5ZUG4vNHNMktexP4AwEgKeF1jKJouVrIs3lAC3e4ZQ==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@sapphire/pieces/-/pieces-3.5.2.tgz", + "integrity": "sha512-B8ghwre5naTIMnJIlqJGhKX6ZTpGqz4oAtBd/ihX0CY69cPtbem3VHfZ8Sf5C+50l3mfe2AU7CfZQn9kLQR2fQ==", "requires": { - "@discordjs/collection": "^1.0.1", - "@sapphire/utilities": "^3.9.2", + "@discordjs/collection": "^1.1.0", + "@sapphire/utilities": "^3.10.0", "tslib": "^2.4.0" } }, "@sapphire/plugin-scheduled-tasks": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.0.tgz", - "integrity": "sha512-MIYiG40HW9kPeZGPcGlLX3uPkKaruG2GIkUhu5gNS1kJogtx6NdZlY5hKBDnpjl1jND5+d2gX9aaLNFA7+UxKA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-scheduled-tasks/-/plugin-scheduled-tasks-4.0.1.tgz", + "integrity": "sha512-vLxfHBu2vKaJZ9v2f4z+VDZaPeDqS8bm+Sc2minRwJPw1hWAHiPqmxCBPIONY7eOQ9qKayvhKYTIwwruxgO/Mg==", "requires": { - "@sapphire/time-utilities": "^1.7.6", + "@sapphire/stopwatch": "^1.4.1", + "@sapphire/utilities": "^3.9.3", "tslib": "^2.4.0" } }, "@sapphire/plugin-subcommands": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.0.0.tgz", - "integrity": "sha512-OLNAIQGEtViG6gYZ5G3/m/Um/mmpH3z7PGRCDv/k7nls9FSvD4Ap7TpeyXFupRI1gT2NJGKOE4TuaHjPwD0k2Q==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@sapphire/plugin-subcommands/-/plugin-subcommands-3.2.3.tgz", + "integrity": "sha512-xUDkHdOXmqquO++I54ZOZg8Prh2YIJ7sSGBLXCU+FiNDbsfzbxr/McCfnKL65L6RBYOjf8d06up3GKPL8t9GpQ==", "requires": { - "@sapphire/utilities": "^3.9.2", + "@sapphire/utilities": "^3.11.0", "tslib": "^2.4.0" } }, "@sapphire/ratelimits": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.4.tgz", - "integrity": "sha512-9gZ1BaY99HLWOcfuhlu0WklirHhVc6QD1pm5/v2W0O9pBpMHrd1GImVMXjYZRoy1qpmE2ZggSmN1665lktTCMw==", + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/@sapphire/ratelimits/-/ratelimits-2.4.5.tgz", + "integrity": "sha512-2wqpVPRaPUE+CWStLm6wGLj1uA4Ln/9qbH4Ue/eCHC6/R5lJz0+8nGD1LpiYOcyeVLTHbmwODGeD92obkPej2g==", "requires": { - "@sapphire/time-utilities": "^1.7.4" + "@sapphire/timer-manager": "^1.0.0" } }, "@sapphire/result": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.4.0.tgz", - "integrity": "sha512-BJkBsXYjTr6nQmKQnUriA1IyQrVDd7rKHTnbk2n03d/sri9ZFYYCRZ8wfFv+Z8QUasFWliypg3Qstz29G1nnjQ==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@sapphire/result/-/result-2.6.0.tgz", + "integrity": "sha512-gdW6n/oDZ8aC1439Ub3RiLQ6L4VHAxbN0AhGJWNkEZ6Z6Ww2V62fwRiA/73OPfgYQKXk9ljhAFiqNO91KAonHQ==" }, "@sapphire/shapeshift": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.5.1.tgz", - "integrity": "sha512-7JFsW5IglyOIUQI1eE0g6h06D/Far6HqpcowRScgCiLSqTf3hhkPWCWotVTtVycnDCMYIwPeaw6IEPBomKC8pA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@sapphire/shapeshift/-/shapeshift-3.7.0.tgz", + "integrity": "sha512-A6vI1zJoxhjWo4grsxpBRBgk96SqSdjLX5WlzKp9H+bJbkM07mvwcbtbVAmUZHbi/OG3HLfiZ1rlw4BhH6tsBQ==", "requires": { "fast-deep-equal": "^3.1.3", "lodash.uniqwith": "^4.5.0" } }, "@sapphire/stopwatch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.4.1.tgz", - "integrity": "sha512-FoZIM7oQ1kwkjWpl/rKReuDFSlkCDjDp//1Np2mmQD+xQ2Zyo/J2MaYAITprwQr3AUBu/OOUJvqm7f8lA9R7gA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@sapphire/stopwatch/-/stopwatch-1.5.0.tgz", + "integrity": "sha512-DtyKugdy3JTqm6JnEepTY64fGJAqlusDVrlrzifEgSCfGYCqpvB+SBldkWtDH+z+zLcp+PyaFLq7xpVfkhmvGg==", "requires": { - "tslib": "^2.3.1" + "tslib": "^2.4.0" } }, - "@sapphire/time-utilities": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@sapphire/time-utilities/-/time-utilities-1.7.6.tgz", - "integrity": "sha512-VsMVYFmS9Iu0buPs7gwn1D6vqIC04ezVMBRIo8vRTB2s7UNN/vQReX2cLABFoDVqs7RHQsvr2DPoTWHEDYw9YA==", - "requires": { - "@sapphire/utilities": "^3.9.2" - } + "@sapphire/timer-manager": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sapphire/timer-manager/-/timer-manager-1.0.0.tgz", + "integrity": "sha512-vxxnv75QPMGKt6IB6nL2xRJfwzcUQ9DBGzJLg6G8eS5O4u7j3IR/yr/GQsa4gIpjw6kQOgn8lUdnSTlpnERTbQ==" }, "@sapphire/ts-config": { "version": "3.3.4", @@ -3619,9 +3706,9 @@ } }, "@sapphire/utilities": { - "version": "3.9.2", - "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.9.2.tgz", - "integrity": "sha512-CG8mFPse+VDUVenj3PqZyh9PATFd/pzrQaX2gZqv0f7AzGnlyfm/ygh0tnQRVKpMDFr39uCQqVse8i0f51DAkg==" + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/@sapphire/utilities/-/utilities-3.11.0.tgz", + "integrity": "sha512-ich7J+329UTEgWxgk8b871rMhbFW/hvXdabdiKaUKd6g10eIMkIakWf+EGkDQsiDSiebIXll9TIPPmWtN3cVSw==" }, "@tsconfig/node10": { "version": "1.0.9", @@ -3665,9 +3752,9 @@ "dev": true }, "@types/node": { - "version": "18.7.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.8.tgz", - "integrity": "sha512-/YP55EMK2341JkODUb8DM9O0x1SIz2aBvyF33Uf1c76St3VpsMXEIW0nxuKkq/5cxnbz0RD9cfwNZHEAZQD3ag==" + "version": "18.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", + "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" }, "@types/node-fetch": { "version": "2.6.2", @@ -3690,11 +3777,6 @@ } } }, - "@types/object-hash": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-2.2.1.tgz", - "integrity": "sha512-i/rtaJFCsPljrZvP/akBqEwUP2y5cZLOmvO+JaYnz01aPknrQ+hB5MRcO7iqCUsFaYfTG8kGfKUyboA07xeDHQ==" - }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -3704,16 +3786,15 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.1.tgz", - "integrity": "sha512-S1iZIxrTvKkU3+m63YUOxYPKaP+yWDQrdhxTglVDVEVBf+aCSw85+BmJnyUaQQsk5TXFG/LpBu9fa+LrAQ91fQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.0.tgz", + "integrity": "sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/type-utils": "5.33.1", - "@typescript-eslint/utils": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/type-utils": "5.40.0", + "@typescript-eslint/utils": "5.40.0", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", "regexpp": "^3.2.0", "semver": "^7.3.7", @@ -3721,52 +3802,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.1.tgz", - "integrity": "sha512-IgLLtW7FOzoDlmaMoXdxG8HOCByTBXrB1V2ZQYSEV1ggMmJfAkMWTwUjjzagS6OkfpySyhKFkBw7A9jYmcHpZA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", + "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/typescript-estree": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.1.tgz", - "integrity": "sha512-8ibcZSqy4c5m69QpzJn8XQq9NnqAToC8OdH/W6IXPXv83vRyEDPYLdjAlUx8h/rbusq6MkW4YdQzURGOqsn3CA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", + "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/visitor-keys": "5.33.1" + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0" } }, "@typescript-eslint/type-utils": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.1.tgz", - "integrity": "sha512-X3pGsJsD8OiqhNa5fim41YtlnyiWMF/eKsEZGsHID2HcDqeSC5yr/uLOeph8rNF2/utwuI0IQoAK3fpoxcLl2g==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.0.tgz", + "integrity": "sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw==", "dev": true, "requires": { - "@typescript-eslint/utils": "5.33.1", + "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/utils": "5.40.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.1.tgz", - "integrity": "sha512-7K6MoQPQh6WVEkMrMW5QOA5FO+BOwzHSNd0j3+BlBwd6vtzfZceJ8xJ7Um2XDi/O3umS8/qDX6jdy2i7CijkwQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", + "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.1.tgz", - "integrity": "sha512-JOAzJ4pJ+tHzA2pgsWQi4804XisPHOtbvwUyqsuuq8+y5B5GMZs7lI1xDWs6V2d7gE/Ez5bTGojSK12+IIPtXA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", + "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/visitor-keys": "5.33.1", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3775,26 +3857,27 @@ } }, "@typescript-eslint/utils": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.1.tgz", - "integrity": "sha512-uphZjkMaZ4fE8CR4dU7BquOV6u0doeQAr8n6cQenl/poMaIyJtBu8eys5uk6u5HiDH01Mj5lzbJ5SfeDz7oqMQ==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.0.tgz", + "integrity": "sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.33.1", - "@typescript-eslint/types": "5.33.1", - "@typescript-eslint/typescript-estree": "5.33.1", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.33.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.1.tgz", - "integrity": "sha512-nwIxOK8Z2MPWltLKMLOEZwmfBZReqUdbEoHQXeCpa+sRVARe5twpJGHCB4dk9903Yaf0nMAlGbQfaAH92F60eg==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", + "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.33.1", + "@typescript-eslint/types": "5.40.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -3914,9 +3997,9 @@ } }, "bullmq": { - "version": "1.89.1", - "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.89.1.tgz", - "integrity": "sha512-VpNFa1buQYDOl4yUF0PxVoCDbh/GT/JeQiaWu/8IdPVMk91RToWtsXvaZdVrfp9VAOtP+F1KJr/pFn+ewY2rnw==", + "version": "1.91.1", + "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-1.91.1.tgz", + "integrity": "sha512-u7dat9I8ZwouZ651AMZkBSvB6NVUPpnAjd4iokd9DM41whqIBnDjuL11h7+kEjcpiDKj6E+wxZiER00FqirZQg==", "requires": { "cron-parser": "^4.6.0", "get-port": "6.1.2", @@ -3926,7 +4009,7 @@ "msgpackr": "^1.6.2", "semver": "^7.3.7", "tslib": "^2.0.0", - "uuid": "^8.3.2" + "uuid": "^9.0.0" } }, "call-bind": { @@ -3956,9 +4039,9 @@ } }, "cluster-key-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", - "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.1.tgz", + "integrity": "sha512-rwHwUfXL40Chm1r08yrhU3qpUvdVlgkKNeyeGPOxnW8/SyVDvgRaed/Uz54AqWNaTCAThlj6QAs3TZcKI0xDEw==" }, "color-convert": { "version": "2.0.1", @@ -4073,21 +4156,40 @@ "integrity": "sha512-dvO5M52v7m7Dy96+XUnzXNsQ/0npsYpU6dL205kAtEDueswoz3aU3bh1UMoK4cQmcGtB1YRyLKqp+DXi05lzFg==" }, "discord.js": { - "version": "13.10.3", - "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.10.3.tgz", - "integrity": "sha512-cIARuxfpQDeqA9Zw3fz4IL20xAhtMsjwJIf7/K82R3n2xROG9/fAx+7qjX8ysp9BfflYqMu2ZskyWq1EAmL5BA==", + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-13.12.0.tgz", + "integrity": "sha512-K5qhREsYcTHkEqt7+7LcSoXTeQYZpI+SQRs9ei/FhbhUpirmjqFtN99P8W2mrKUyhhy7WXWm7rnna0AooKtIpw==", "requires": { "@discordjs/builders": "^0.16.0", "@discordjs/collection": "^0.7.0", "@sapphire/async-queue": "^1.5.0", "@types/node-fetch": "^2.6.2", "@types/ws": "^8.5.3", - "discord-api-types": "^0.33.3", + "discord-api-types": "^0.33.5", "form-data": "^4.0.0", "node-fetch": "^2.6.7", - "ws": "^8.8.1" + "ws": "^8.9.0" }, "dependencies": { + "@discordjs/builders": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-0.16.0.tgz", + "integrity": "sha512-9/NCiZrLivgRub2/kBc0Vm5pMBE5AUdYbdXsLu/yg9ANgvnaJ0bZKTY8yYnLbsEc/LYUP79lEIdC73qEYhWq7A==", + "requires": { + "@sapphire/shapeshift": "^3.5.1", + "discord-api-types": "^0.36.2", + "fast-deep-equal": "^3.1.3", + "ts-mixer": "^6.0.1", + "tslib": "^2.4.0" + }, + "dependencies": { + "discord-api-types": { + "version": "0.36.3", + "resolved": "https://registry.npmjs.org/discord-api-types/-/discord-api-types-0.36.3.tgz", + "integrity": "sha512-bz/NDyG0KBo/tY14vSkrwQ/n3HKPf87a0WFW/1M9+tXYK+vp5Z5EksawfCWo2zkAc6o7CClc0eff1Pjrqznlwg==" + } + } + }, "@discordjs/collection": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.7.0.tgz", @@ -4105,36 +4207,37 @@ } }, "dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", + "integrity": "sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==" }, "es-abstract": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", - "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", "function.prototype.name": "^1.1.5", - "get-intrinsic": "^1.1.1", + "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", "is-weakref": "^1.0.2", - "object-inspect": "^1.12.0", + "object-inspect": "^1.12.2", "object-keys": "^1.1.1", - "object.assign": "^4.1.2", + "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", "string.prototype.trimend": "^1.0.5", "string.prototype.trimstart": "^1.0.5", "unbox-primitive": "^1.0.2" @@ -4167,14 +4270,14 @@ "dev": true }, "eslint": { - "version": "8.22.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz", - "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==", + "version": "8.25.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.25.0.tgz", + "integrity": "sha512-DVlJOZ4Pn50zcKW5bYH7GQK/9MsoQG2d5eDH0ebEkE8PbgzTTmtt/VTH9GGJ4BfeZCpBLqFfvsjX35UacUL83A==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.10.4", - "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/module-importer": "^1.0.1", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -4184,13 +4287,12 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.3", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -4199,6 +4301,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -4209,8 +4312,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "eslint-scope": { @@ -4382,9 +4484,9 @@ "dev": true }, "espree": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", - "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.0.tgz", + "integrity": "sha512-DQmnRpLj7f6TgN/NYb0MTzJXL+vJF9h3pHy4JhCIs3zwcgez8xmGg3sXHcEO97BrmO2OSvCwMdfdlyl+E9KjOw==", "dev": true, "requires": { "acorn": "^8.8.0", @@ -4444,9 +4546,9 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4565,12 +4667,6 @@ "functions-have-names": "^1.2.2" } }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true - }, "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", @@ -4578,9 +4674,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.2.tgz", - "integrity": "sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -4764,9 +4860,9 @@ } }, "ioredis": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.2.tgz", - "integrity": "sha512-wryKc1ur8PcCmNwfcGkw5evouzpbDXxxkMkzPK8wl4xQfQf7lHe11Jotell5ikMVAtikXJEu/OJVaoV51BggRQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.3.tgz", + "integrity": "sha512-gQNcMF23/NpvjCaa1b5YycUyQJ9rBNH2xP94LWinNpodMWVUPP5Ai/xXANn/SM7gfIvI62B5CCvZxhg5pOgyMw==", "requires": { "@ioredis/commands": "^1.1.1", "cluster-key-slot": "^1.1.0", @@ -4799,9 +4895,9 @@ } }, "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true }, "is-core-module": { @@ -4910,6 +5006,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "js-sdsl": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", + "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "dev": true + }, "js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -4994,9 +5096,9 @@ } }, "luxon": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.1.tgz", - "integrity": "sha512-hF3kv0e5gwHQZKz4wtm4c+inDtyc7elkanAsBq+fundaCdUBNJB1dHEGUZIM6SfSBUlbVFduPwEtNjFK8wLtcw==" + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/luxon/-/luxon-3.0.4.tgz", + "integrity": "sha512-aV48rGUwP/Vydn8HT+5cdr26YYQiUZ42NM6ToMoaGKwYfWbfLeRkEu1wXWMHBZT6+KyLfcbbtVcoQFCbbPjKlw==" }, "make-error": { "version": "1.3.6", @@ -5042,9 +5144,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "ms": { @@ -5053,11 +5155,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "msgpackr": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.6.2.tgz", - "integrity": "sha512-bqSQ0DYJbXbrJcrZFmMygUZmqQiDfI2ewFVWcrZY12w5XHWtPuW4WppDT/e63Uu311ajwkRRXSoF0uILroBeTA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.7.2.tgz", + "integrity": "sha512-mWScyHTtG6TjivXX9vfIy2nBtRupaiAj0HQ2mtmpmYujAmqZmaaEVPaSZ1NKLMvicaMLFzEaMk0ManxMRg8rMQ==", "requires": { - "msgpackr-extract": "^2.0.2" + "msgpackr-extract": "^2.1.2" } }, "msgpackr-extract": { @@ -5095,11 +5197,6 @@ "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", "optional": true }, - "object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" - }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -5238,12 +5335,12 @@ "dev": true }, "prisma": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.2.1.tgz", - "integrity": "sha512-HuYqnTDgH8atjPGtYmY0Ql9XrrJnfW7daG1PtAJRW0E6gJxc50lY3vrIDn0yjMR3TvRlypjTcspQX8DT+xD4Sg==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", "devOptional": true, "requires": { - "@prisma/engines": "4.2.1" + "@prisma/engines": "4.4.0" } }, "punycode": { @@ -5345,10 +5442,21 @@ "queue-microtask": "^1.2.2" } }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "requires": { "lru-cache": "^6.0.0" } @@ -5543,9 +5651,9 @@ "dev": true }, "typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==" }, "unbox-primitive": { "version": "1.0.2", @@ -5569,15 +5677,9 @@ } }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" - }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "v8-compile-cache-lib": { "version": "3.0.1", @@ -5632,9 +5734,9 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "ws": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.1.tgz", - "integrity": "sha512-bGy2JzvzkPowEJV++hF07hAD6niYSr0JzBNo/J29WsB57A2r7Wlc1UFcTR9IzrPvuNVO4B8LGqF8qcpsVOhJCA==", + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", "requires": {} }, "yallist": { diff --git a/package.json b/package.json index 39ae8c9..e967198 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "homepage": "https://github.com/veganhacktivists/arabot#readme", "dependencies": { + "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", "@sapphire/framework": "^3.0.0", @@ -50,6 +51,6 @@ "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.0.0", "eslint-plugin-import": "^2.26.0", - "prisma": "^4.2.1" + "prisma": "^4.4.0" } } From 9cc7e53ea91cae17ce0616b458934b8d84c933ef Mon Sep 17 00:00:00 2001 From: smyalygames Date: Sun, 16 Oct 2022 22:55:11 +0100 Subject: [PATCH 47/57] feat(verify): add verify block dm for timeout/leave --- src/listeners/verification/leaveVC.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 392f34e..10b7e33 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -21,6 +21,7 @@ import { container, Listener } from '@sapphire/framework'; import type { VoiceState, CategoryChannel, VoiceChannel, TextChannel, } from 'discord.js'; +import { time } from '@discordjs/builders'; import { maxVCs, leaveBan } from '../../utils/verificationConfig'; import { getUser, checkFinish, countIncomplete } from '../../utils/database/verification'; import { fetchRoles } from '../../utils/database/dbExistingUser'; @@ -94,6 +95,9 @@ class VerificationLeaveVCListener extends Listener { userId: user.id, guildId: guild.id, }, banLength); + + await user.user.send('You have disconnected or been timed out as a verifier had not joined for 15 minutes from Verification.\n\n' + + `You can verify again at: ${time(Math.round(Date.now() / 1000) + (banLength / 1000))}`); } } From e0207fdd8d5b8c4b4f7adb2f93a99ef81f841fb3 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Wed, 19 Oct 2022 01:59:49 +0100 Subject: [PATCH 48/57] feat(verify): add welcome message after verify --- src/listeners/verification/joinVC.ts | 52 ++++++++++++++++++++++++++++ src/utils/devIDs.ts | 13 +++++++ src/utils/ids.ts | 13 +++++++ 3 files changed, 78 insertions(+) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 0dd6c36..872ed06 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -26,6 +26,7 @@ import type { VoiceState, GuildMember, Guild, + User, } from 'discord.js'; import { ButtonInteraction, @@ -517,6 +518,8 @@ class VerificationJoinVCListener extends Listener { embeds: [embed], components: [], }); + // Send welcome message after verification + await this.finishMessages(user.user, info.roles); } }); } @@ -618,6 +621,55 @@ class VerificationJoinVCListener extends Listener { } await user.roles.add(rolesAdd); } + + // Messages after verifying the user + private async finishMessages(user: User, roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }) { + // Not vegan + if (!roles.vegan) { + const general = this.container.client.channels.cache.get(IDs.channels.nonVegan.general) as TextChannel | undefined; + if (general === undefined) { + return; + } + let msg = `${user}, you have been verified! Please check <#${IDs.channels.information.roles}> ` + + `and remember to follow the <#${IDs.channels.information.conduct}> and to respect ongoing discussion and debates.`; + // Add extra info if the user got veg curious or convinced. + if (roles.vegCurious || roles.convinced) { + msg += `\n\nYou also have access to <#${IDs.channels.dietSupport.main}> for help on going vegan.`; + } + await general.send(msg); + return; + } + + // Vegan + const general = this.container.client.channels.cache.get(IDs.channels.vegan.general) as TextChannel | undefined; + if (general === undefined) { + return; + } + const msg = `Welcome ${user}! Please check out <#${IDs.channels.information.roles}> :)`; + await general.send(msg); + + // Activist role + if (roles.activist) { + const activist = this.container.client.channels.cache.get(IDs.channels.activism.activism) as TextChannel | undefined; + if (activist === undefined) { + return; + } + const activistMsg = `${user} you have been given the activist role! This means that if you'd wish to engage with non-vegans in ` + + `<#${IDs.channels.nonVegan.general}>, you should follow these rules:\n\n` + + '1. Try to move conversations with non-vegans towards veganism/animal ethics\n' + + '2. Don\'t discuss social topics while activism is happening\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' + + '5. Differences in opinion between activists should be resolved in vegan spaces, not in the chat with non-vegans'; + await activist.send(activistMsg); + } + } } export default VerificationJoinVCListener; diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index 9493355..772c2e9 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -59,15 +59,28 @@ const devIDs = { channels: { information: { news: '999431676058927247', + conduct: '999431676058927248', + roles: '999431676058927250', }, staff: { coordinators: '999431676058927254', standup: '999431676289622183', verifiers: '999431677006860411', }, + dietSupport: { + info: '999431677006860417', + introduction: '999431677325615184', + main: '999431677325615185', + }, nonVegan: { general: '999431677325615189', }, + vegan: { + general: '999431677535338575', + }, + activism: { + activism: '999431678214807604', + }, diversity: { women: '999431679053660187', lgbtqia: '999431679053660188', diff --git a/src/utils/ids.ts b/src/utils/ids.ts index 81b9eef..ec52e28 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -62,15 +62,28 @@ let IDs = { channels: { information: { news: '866000393259319306', + conduct: '990728521531920385', + roles: '990761562199457813', }, staff: { coordinators: '1006240682505142354', standup: '996009201237233684', verifiers: '873215538627756072', }, + dietSupport: { + info: '993891104346873888', + introduction: '993272252743286874', + main: '822665615612837918', + }, nonVegan: { general: '798967615636504657', }, + vegan: { + general: '787738272616808509', + }, + activism: { + activism: '730907954877956179', + }, diversity: { women: '938808963544285324', lgbtqia: '956224226556272670', From 7f3f31d9f00598c3c085fed9ba1c591c52444b6d Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 13:43:29 +0100 Subject: [PATCH 49/57] feat(verify): add give roles on join --- src/listeners/verification/joinServer.ts | 57 ++++++++++++++++++++++++ src/utils/database/verification.ts | 41 +++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/listeners/verification/joinServer.ts diff --git a/src/listeners/verification/joinServer.ts b/src/listeners/verification/joinServer.ts new file mode 100644 index 0000000..fc834a3 --- /dev/null +++ b/src/listeners/verification/joinServer.ts @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2022 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 . +*/ + +import { Listener } from '@sapphire/framework'; +import type { GuildMember } from 'discord.js'; +import { fetchRoles } from '../../utils/database/dbExistingUser'; +import IDs from '../../utils/ids'; +import { blockTime } from '../../utils/database/verification'; + +class VerificationReady extends Listener { + public constructor(context: Listener.Context, options: Listener.Options) { + super(context, { + ...options, + once: true, + event: 'guildMemberAdd', + }); + } + + public async run(user: GuildMember) { + // Add basic roles + const roles = await fetchRoles(user.id); + + // Check if the user has a verification block + const timeout = await blockTime(user.id); + if (timeout > 0) { + roles.push(IDs.roles.verifyBlock); + await user.roles.add(roles); + + // @ts-ignore + this.container.tasks.create('verifyUnblock', { + userId: user.id, + guildId: user.guild.id, + }, timeout); + } else { + // Add roles if they don't have verification block + await user.roles.add(roles); + } + } +} + +export default VerificationReady; diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index b444424..05e6c14 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -20,6 +20,8 @@ import type { GuildMember } from 'discord.js'; import { PrismaClient } from '@prisma/client'; import { updateUser } from './dbExistingUser'; +import { leaveBan } from '../verificationConfig'; +import { fibonacci } from '../mathsSeries'; export async function joinVerification(channelId: string, user: GuildMember) { // Update the user on the database with the current roles they have @@ -187,3 +189,42 @@ export async function countIncomplete(userId: string) { return incompleteCount; } + +// Gets the amount of time left on the block +export async function blockTime(userId: string) { + // Initialises Prisma Client + const prisma = new PrismaClient(); + + // Count how many times the user has not completed a verification + const verification = await prisma.verify.findFirst({ + where: { + userId, + }, + orderBy: { + id: 'desc', + }, + }); + + // Close the database connection + await prisma.$disconnect(); + + if (verification === null) { + return 0; + } + + // If user finished verification + if (verification.finishTime !== null) { + // Activist role + if (verification.activist) { + return 0; + } + const timeOff = new Date().getMilliseconds() - verification.finishTime.getMilliseconds(); + return ((verification.vegan || verification.convinced) ? 604800000 : 1814400000) - timeOff; + } + + // Timeouts + const count = await countIncomplete(verification.userId) % (leaveBan + 1); + const timeOff = new Date().getMilliseconds() - verification.joinTime.getMilliseconds(); + // Creates the length of the time for the ban + return (fibonacci(count) * 10000) - timeOff; // TODO * 3600 commented because development +} From 44d913b863f5525ce66de85d84a286c1ccea6c29 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 16:44:26 +0100 Subject: [PATCH 50/57] fix(verify): change getMillisecond to getTime --- src/listeners/verification/joinServer.ts | 13 +++---------- src/utils/database/verification.ts | 4 ++-- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/listeners/verification/joinServer.ts b/src/listeners/verification/joinServer.ts index fc834a3..a305481 100644 --- a/src/listeners/verification/joinServer.ts +++ b/src/listeners/verification/joinServer.ts @@ -40,17 +40,10 @@ class VerificationReady extends Listener { const timeout = await blockTime(user.id); if (timeout > 0) { roles.push(IDs.roles.verifyBlock); - await user.roles.add(roles); - - // @ts-ignore - this.container.tasks.create('verifyUnblock', { - userId: user.id, - guildId: user.guild.id, - }, timeout); - } else { - // Add roles if they don't have verification block - await user.roles.add(roles); } + + // Add roles if they don't have verification block + await user.roles.add(roles); } } diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index 05e6c14..7624f7a 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -218,13 +218,13 @@ export async function blockTime(userId: string) { if (verification.activist) { return 0; } - const timeOff = new Date().getMilliseconds() - verification.finishTime.getMilliseconds(); + const timeOff = new Date().getTime() - verification.finishTime.getTime(); return ((verification.vegan || verification.convinced) ? 604800000 : 1814400000) - timeOff; } // Timeouts const count = await countIncomplete(verification.userId) % (leaveBan + 1); - const timeOff = new Date().getMilliseconds() - verification.joinTime.getMilliseconds(); + const timeOff = new Date().getTime() - verification.joinTime.getTime(); // Creates the length of the time for the ban return (fibonacci(count) * 10000) - timeOff; // TODO * 3600 commented because development } From 4314e3a08366d3404455285aa4b4df75f60b018f Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 16:44:51 +0100 Subject: [PATCH 51/57] fix(verify): add a catch for closed DMs --- src/listeners/verification/leaveVC.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 10b7e33..784a433 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -96,8 +96,9 @@ class VerificationLeaveVCListener extends Listener { guildId: guild.id, }, banLength); - await user.user.send('You have disconnected or been timed out as a verifier had not joined for 15 minutes from Verification.\n\n' - + `You can verify again at: ${time(Math.round(Date.now() / 1000) + (banLength / 1000))}`); + await user.user.send('You have been timed out as a verifier had not joined for 15 minutes or you disconnected from verification.\n\n' + + `You can verify again at: ${time(Math.round(Date.now() / 1000) + (banLength / 1000))}`) + .catch(() => console.error('Verification: Closed DMs')); } } From 6f694d94fb73d032628f458a3fd765648b7e5b8a Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 16:45:09 +0100 Subject: [PATCH 52/57] build(arabot): update all packages --- package-lock.json | 258 ++++++++++++++++++++++++---------------------- package.json | 4 +- 2 files changed, 138 insertions(+), 124 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a29a98..643f5ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/framework": "^3.0.0", + "@sapphire/framework": "^3.1.3", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", @@ -20,7 +20,7 @@ "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.3", + "discord.js": "^13.12.0", "dotenv": "^16.0.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" @@ -276,12 +276,12 @@ } }, "node_modules/@prisma/client": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", - "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.5.0.tgz", + "integrity": "sha512-B2cV0OPI1smhdYUxsJoLYQLoMlLH06MUxgFUWQnHodGMX98VRVXKmQE/9OcrTNkqtke5RC+YU24Szxd04tZA2g==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + "@prisma/engines-version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452" }, "engines": { "node": ">=14.17" @@ -296,16 +296,16 @@ } }, "node_modules/@prisma/engines": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", - "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.5.0.tgz", + "integrity": "sha512-4t9ir2SbQQr/wMCNU4YpHWp5hU14J2m3wHUZnGJPpmBF8YtkisxyVyQsKd1e6FyLTaGq8LOLhm6VLYHKqKNm+g==", "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", - "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + "version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452.tgz", + "integrity": "sha512-o7LyVx8PPJBLrEzLl6lpxxk2D5VnlM4Fwmrbq0NoT6pr5aa1OuHD9ZG+WJY6TlR/iD9bhmo2LNcxddCMr5Rv2A==" }, "node_modules/@sapphire/async-queue": { "version": "1.5.0", @@ -564,9 +564,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", - "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" + "version": "18.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", + "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==" }, "node_modules/@types/node-fetch": { "version": "2.6.2", @@ -590,6 +590,12 @@ "node": ">= 6" } }, + "node_modules/@types/semver": { + "version": "7.3.12", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", + "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -599,14 +605,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.0.tgz", - "integrity": "sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", + "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/type-utils": "5.40.0", - "@typescript-eslint/utils": "5.40.0", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/type-utils": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "ignore": "^5.2.0", "regexpp": "^3.2.0", @@ -631,14 +637,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", - "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", + "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "debug": "^4.3.4" }, "engines": { @@ -658,13 +664,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", - "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", + "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0" + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -675,13 +681,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.0.tgz", - "integrity": "sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", + "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.40.0", - "@typescript-eslint/utils": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -702,9 +708,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", - "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", + "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -715,13 +721,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", - "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", + "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -742,15 +748,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.0.tgz", - "integrity": "sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", + "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -767,12 +774,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", - "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", + "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/types": "5.40.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2133,9 +2140,9 @@ } }, "node_modules/is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "dependencies": { "has": "^1.0.3" @@ -2742,13 +2749,13 @@ } }, "node_modules/prisma": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", - "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz", + "integrity": "sha512-9Aeg4qiKlv9Wsjz4NO8k2CzRzlvS3A4FYVJ5+28sBBZ0eEwbiVOE/Jj7v6rZC1tFW2s4GSICQOAyuOjc6WsNew==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "4.4.0" + "@prisma/engines": "4.5.0" }, "bin": { "prisma": "build/index.js", @@ -3543,23 +3550,23 @@ } }, "@prisma/client": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", - "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.5.0.tgz", + "integrity": "sha512-B2cV0OPI1smhdYUxsJoLYQLoMlLH06MUxgFUWQnHodGMX98VRVXKmQE/9OcrTNkqtke5RC+YU24Szxd04tZA2g==", "requires": { - "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + "@prisma/engines-version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452" } }, "@prisma/engines": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", - "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.5.0.tgz", + "integrity": "sha512-4t9ir2SbQQr/wMCNU4YpHWp5hU14J2m3wHUZnGJPpmBF8YtkisxyVyQsKd1e6FyLTaGq8LOLhm6VLYHKqKNm+g==", "devOptional": true }, "@prisma/engines-version": { - "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", - "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + "version": "4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.5.0-43.0362da9eebca54d94c8ef5edd3b2e90af99ba452.tgz", + "integrity": "sha512-o7LyVx8PPJBLrEzLl6lpxxk2D5VnlM4Fwmrbq0NoT6pr5aa1OuHD9ZG+WJY6TlR/iD9bhmo2LNcxddCMr5Rv2A==" }, "@sapphire/async-queue": { "version": "1.5.0", @@ -3752,9 +3759,9 @@ "dev": true }, "@types/node": { - "version": "18.11.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", - "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==" + "version": "18.11.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.3.tgz", + "integrity": "sha512-fNjDQzzOsZeKZu5NATgXUPsaFaTxeRgFXoosrHivTl8RGeV733OLawXsGfEk9a8/tySyZUyiZ6E8LcjPFZ2y1A==" }, "@types/node-fetch": { "version": "2.6.2", @@ -3777,6 +3784,12 @@ } } }, + "@types/semver": { + "version": "7.3.12", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.12.tgz", + "integrity": "sha512-WwA1MW0++RfXmCr12xeYOOC5baSC9mSb0ZqCquFzKhcoF4TvHu5MKOuXsncgZcpVFhB1pXd5hZmM0ryAoCp12A==", + "dev": true + }, "@types/ws": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", @@ -3786,14 +3799,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.0.tgz", - "integrity": "sha512-FIBZgS3DVJgqPwJzvZTuH4HNsZhHMa9SjxTKAZTlMsPw/UzpEjcf9f4dfgDJEHjK+HboUJo123Eshl6niwEm/Q==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.40.1.tgz", + "integrity": "sha512-FsWboKkWdytGiXT5O1/R9j37YgcjO8MKHSUmWnIEjVaz0krHkplPnYi7mwdb+5+cs0toFNQb0HIrN7zONdIEWg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/type-utils": "5.40.0", - "@typescript-eslint/utils": "5.40.0", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/type-utils": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "ignore": "^5.2.0", "regexpp": "^3.2.0", @@ -3802,53 +3815,53 @@ } }, "@typescript-eslint/parser": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", - "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.1.tgz", + "integrity": "sha512-IK6x55va5w4YvXd4b3VrXQPldV9vQTxi5ov+g4pMANsXPTXOcfjx08CRR1Dfrcc51syPtXHF5bgLlMHYFrvQtg==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", - "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.1.tgz", + "integrity": "sha512-jkn4xsJiUQucI16OLCXrLRXDZ3afKhOIqXs4R3O+M00hdQLKR58WuyXPZZjhKLFCEP2g+TXdBRtLQ33UfAdRUg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0" + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1" } }, "@typescript-eslint/type-utils": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.0.tgz", - "integrity": "sha512-nfuSdKEZY2TpnPz5covjJqav+g5qeBqwSHKBvz7Vm1SAfy93SwKk/JeSTymruDGItTwNijSsno5LhOHRS1pcfw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.40.1.tgz", + "integrity": "sha512-DLAs+AHQOe6n5LRraXiv27IYPhleF0ldEmx6yBqBgBLaNRKTkffhV1RPsjoJBhVup2zHxfaRtan8/YRBgYhU9Q==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.40.0", - "@typescript-eslint/utils": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.1", + "@typescript-eslint/utils": "5.40.1", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", - "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.1.tgz", + "integrity": "sha512-Icg9kiuVJSwdzSQvtdGspOlWNjVDnF3qVIKXdJ103o36yRprdl3Ge5cABQx+csx960nuMF21v8qvO31v9t3OHw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", - "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.1.tgz", + "integrity": "sha512-5QTP/nW5+60jBcEPfXy/EZL01qrl9GZtbgDZtDPlfW5zj/zjNrdI2B5zMUHmOsfvOr2cWqwVdWjobCiHcedmQA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/visitor-keys": "5.40.0", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/visitor-keys": "5.40.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3857,27 +3870,28 @@ } }, "@typescript-eslint/utils": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.0.tgz", - "integrity": "sha512-MO0y3T5BQ5+tkkuYZJBjePewsY+cQnfkYeRqS6tPh28niiIwPnQ1t59CSRcs1ZwJJNOdWw7rv9pF8aP58IMihA==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.40.1.tgz", + "integrity": "sha512-a2TAVScoX9fjryNrW6BZRnreDUszxqm9eQ9Esv8n5nXApMW0zeANUYlwh/DED04SC/ifuBvXgZpIK5xeJHQ3aw==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.40.0", - "@typescript-eslint/types": "5.40.0", - "@typescript-eslint/typescript-estree": "5.40.0", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.40.1", + "@typescript-eslint/types": "5.40.1", + "@typescript-eslint/typescript-estree": "5.40.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.40.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", - "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", + "version": "5.40.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.1.tgz", + "integrity": "sha512-A2DGmeZ+FMja0geX5rww+DpvILpwo1OsiQs0M+joPWJYsiEFBLsH0y1oFymPNul6Z5okSmHpP4ivkc2N0Cgfkw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/types": "5.40.1", "eslint-visitor-keys": "^3.3.0" } }, @@ -4901,9 +4915,9 @@ "dev": true }, "is-core-module": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", - "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, "requires": { "has": "^1.0.3" @@ -5335,12 +5349,12 @@ "dev": true }, "prisma": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", - "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.5.0.tgz", + "integrity": "sha512-9Aeg4qiKlv9Wsjz4NO8k2CzRzlvS3A4FYVJ5+28sBBZ0eEwbiVOE/Jj7v6rZC1tFW2s4GSICQOAyuOjc6WsNew==", "devOptional": true, "requires": { - "@prisma/engines": "4.4.0" + "@prisma/engines": "4.5.0" } }, "punycode": { diff --git a/package.json b/package.json index e967198..e780dee 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@discordjs/builders": "^1.3.0", "@prisma/client": "^4.0.0", "@sapphire/discord.js-utilities": "^5.0.0", - "@sapphire/framework": "^3.0.0", + "@sapphire/framework": "^3.1.3", "@sapphire/plugin-scheduled-tasks": "^4.0.0", "@sapphire/plugin-subcommands": "^3.0.0", "@sapphire/stopwatch": "^1.4.1", @@ -37,7 +37,7 @@ "@types/node": "^18.0.3", "bullmq": "^1.89.1", "discord-api-types": "^0.33.3", - "discord.js": "^13.10.3", + "discord.js": "^13.12.0", "dotenv": "^16.0.1", "ts-node": "^10.8.2", "typescript": "^4.7.4" From 3c0472ecccc4f16f90381ac3c4d35b9cc84b4353 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 18:45:38 +0100 Subject: [PATCH 53/57] feat(verify): add DM msg after verification --- src/listeners/verification/joinVC.ts | 32 +++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 872ed06..5414421 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -138,7 +138,7 @@ class VerificationJoinVCListener extends Listener { this.container.tasks.create('verifyTimeout', { channelId: channel.id, userId: member.id, - }, 30_000); // TODO change before production to 15 mins + }, 900_000); // 15 minutes } // Check how many voice channels there are @@ -630,6 +630,10 @@ class VerificationJoinVCListener extends Listener { vegCurious: boolean, convinced: boolean }) { + // Send a DM with when their verification is finished + await this.finishDM(user, roles) + .catch(() => console.error('Verification: Closed DMs')); + // Not vegan if (!roles.vegan) { const general = this.container.client.channels.cache.get(IDs.channels.nonVegan.general) as TextChannel | undefined; @@ -670,6 +674,32 @@ class VerificationJoinVCListener extends Listener { await activist.send(activistMsg); } } + + // Messages after verifying the user + private async finishDM(user: User, roles: { + vegan: boolean, + activist: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }) { + if (!roles.vegan && !roles.convinced) { + const message = 'You\'ve been verified as non-vegan!' + + `\n\nYou can next verify on ${time(Math.round(Date.now() / 1000) + 1814400)}`; + + await user.send(message); + } else if (roles.convinced) { + const message = 'You\'ve been verified as convinced!' + + `\n\nYou can next verify on ${time(Math.round(Date.now() / 1000) + 604800)}`; + + await user.send(message); + } else if (roles.vegan && !roles.activist) { + const message = 'You\'ve been verified as a vegan!' + + `\n\nYou can next get verified on ${time(Math.round(Date.now() / 1000) + 604800)} if you would wish to have the activist role.`; + + await user.send(message); + } + } } export default VerificationJoinVCListener; From 989915b7966127d6d6f6a66556f58a1774fa9192 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 22:14:31 +0100 Subject: [PATCH 54/57] feat(verify): add cancel for roles to give in verification --- src/listeners/verification/joinVC.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 5414421..8dfd570 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -521,6 +521,21 @@ class VerificationJoinVCListener extends Listener { // Send welcome message after verification await this.finishMessages(user.user, info.roles); } + if (button.customId === 'cancel' && info.page >= questionLength) { + info.page = 5; + info.roles.vegan = false; + info.roles.activist = false; + info.roles.trusted = false; + info.roles.vegCurious = false; + info.roles.convinced = false; + embed = await this.createEmbed(questionInfo[info.page].question, embedColor); + buttons = await this.createButtons(questionInfo[info.page].buttons); + await message.edit({ + embeds: [embed], + components: buttons, + }); + await button.deferUpdate(); + } }); } From a8efff58710061d626ab29c3226dcae018f225d3 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 22:18:57 +0100 Subject: [PATCH 55/57] refactor(verify): change timeout values for production --- src/listeners/verification/leaveVC.ts | 2 +- src/utils/database/verification.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/listeners/verification/leaveVC.ts b/src/listeners/verification/leaveVC.ts index 784a433..47a64c8 100644 --- a/src/listeners/verification/leaveVC.ts +++ b/src/listeners/verification/leaveVC.ts @@ -88,7 +88,7 @@ class VerificationLeaveVCListener extends Listener { // Counts the recent times they have incomplete verifications const incompleteCount = await countIncomplete(user.id) % (leaveBan + 1); // Creates the length of the time for the ban - const banLength = fibonacci(incompleteCount) * 10000; // TODO * 3600 commented because development + const banLength = fibonacci(incompleteCount) * 3600_000; // @ts-ignore this.container.tasks.create('verifyUnblock', { diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index 7624f7a..410dd7f 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -226,5 +226,5 @@ export async function blockTime(userId: string) { const count = await countIncomplete(verification.userId) % (leaveBan + 1); const timeOff = new Date().getTime() - verification.joinTime.getTime(); // Creates the length of the time for the ban - return (fibonacci(count) * 10000) - timeOff; // TODO * 3600 commented because development + return (fibonacci(count) * 3600_000) - timeOff; } From 92ebf948f09efadb74cc6fce4409de4c584149a5 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 22:23:58 +0100 Subject: [PATCH 56/57] feat(verify): add verification block role id --- src/utils/ids.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/ids.ts b/src/utils/ids.ts index ec52e28..1193d54 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -57,7 +57,7 @@ let IDs = { patron: '765370219207852055', patreon: '993848684640997406', verifyingAsVegan: '854725899576279060', - verifyBlock: '', + verifyBlock: '1032765019269640203', }, channels: { information: { From d460826c4388cf8a1c6845ee7b8b46356a811cf1 Mon Sep 17 00:00:00 2001 From: smyalygames Date: Thu, 20 Oct 2022 22:25:04 +0100 Subject: [PATCH 57/57] feat(verify): delete apple warning --- src/scheduled-tasks/appleWarning.ts | 50 ----------------------------- 1 file changed, 50 deletions(-) delete mode 100644 src/scheduled-tasks/appleWarning.ts diff --git a/src/scheduled-tasks/appleWarning.ts b/src/scheduled-tasks/appleWarning.ts deleted file mode 100644 index 22305ac..0000000 --- a/src/scheduled-tasks/appleWarning.ts +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -/* - Animal Rights Advocates Discord Bot - Copyright (C) 2022 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 . -*/ - -import { ScheduledTask } from '@sapphire/plugin-scheduled-tasks'; -import { container } from '@sapphire/framework'; -import type { TextChannel } from 'discord.js'; -import IDs from '../utils/ids'; - -class AppleWarningTask extends ScheduledTask { - public constructor(context: ScheduledTask.Context, options: ScheduledTask.Options) { - super(context, { - ...options, - cron: '0 */2 * * 2-3', - }); - } - - public async run() { - const { client } = container; - - const channel = client.channels.cache.get(IDs.channels.nonVegan.general) as TextChannel; - - await channel.send('Hiya everyone, this is a warning to all **Apple users**!\n' - + 'Make sure to update your iOS, iPadOS and MacOS as there is a hack that lets anyone get remote access to your device if you click on a malicious link.\n' - + `For more information, read the post in <#${IDs.channels.information.news}>`); - } -} - -declare module '@sapphire/plugin-scheduled-tasks' { - interface ScheduledTasks { - cron: never; - } -} - -export default AppleWarningTask;