From f333c5090de238a01af0f3702ae9cb7e1be482d6 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 30 Jul 2022 02:23:17 +0100 Subject: [PATCH] feat(docs): add purgeverifying command --- src/commands/verification/purgeVerifying.ts | 124 +++++++++++++++++++ src/preconditions/VerifierCoordinatorOnly.ts | 52 ++++++++ src/utils/ids.ts | 2 + 3 files changed, 178 insertions(+) create mode 100644 src/commands/verification/purgeVerifying.ts create mode 100644 src/preconditions/VerifierCoordinatorOnly.ts diff --git a/src/commands/verification/purgeVerifying.ts b/src/commands/verification/purgeVerifying.ts new file mode 100644 index 0000000..29e6d04 --- /dev/null +++ b/src/commands/verification/purgeVerifying.ts @@ -0,0 +1,124 @@ +// 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 { Command, RegisterBehavior } from '@sapphire/framework'; +import { isMessageInstance } from '@sapphire/discord.js-utilities'; +import { IDs } from '../../utils/ids'; + +export class purgeVerifyingCommand extends Command { + public constructor(context: Command.Context, options: Command.Options) { + super(context, { + ...options, + name: 'purgeverifying', + description: 'Purges all the users who have the "verify-as-vegan" role', + preconditions: ['VerifierCoordinatorOnly'], + }); + } + + // Registers that this is a slash command + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand( + (builder) => builder + .setName(this.name) + .setDescription(this.description), + { + behaviorWhenNotIdentical: RegisterBehavior.Overwrite, + }, + ); + } + + // Command run + public async chatInputRun(interaction: Command.ChatInputInteraction) { + // TODO add database updates + // Get the arguments + const { guild } = interaction; + + // Checks if all the variables are of the right type + if (guild === null) { + await interaction.reply({ + content: 'Error getting guild!', + ephemeral: true, + fetchReply: true, + }); + return; + } + + const message = await interaction.reply({ + content: 'Fetching all members on the server, this may take a while...', + fetchReply: true, + }); + + // Checks if the message is not an APIMessage + if (!isMessageInstance(message)) { + await interaction.editReply('Failed to retrieve the message :('); + return; + } + + // Get all the members + await guild!.members.fetch(); + // Gets the verify-as-vegan and Not Vegan role + const getVerVegan = guild!.roles.cache.get(IDs.roles.verifyingAsVegan); + const getNotVegan = guild!.roles.cache.get(IDs.roles.nonvegan.nonvegan); + + // Checks if getVerVegan or getNotVegan is null + if (getVerVegan === null || getNotVegan === null) { + await interaction.reply({ + content: 'Error getting roles!', + ephemeral: true, + fetchReply: true, + }); + return; + } + + // Gets all users that have the verify-as-vegan role + const verVegan = getVerVegan!.members.map((member) => member); + const verVeganLength = verVegan.length; + const apiTimeout = 2500; + + function calcETA(timeout: number, increment: number, endIncrement: number) { + const minutes = Math.floor(((timeout / 1000) * (endIncrement - increment - 1)) / 60); + const seconds = Math.floor((timeout / 1000) * (endIncrement - increment - 1)) + - (minutes * 60); + return `${minutes}:${(seconds < 10 ? '0' : '') + seconds}`; + } + + // Goes through every member with the verify-as-vegan role + for (let i = 0; i < verVeganLength; i++) { + const member = verVegan[i]; + // Runs command based on apiTimeout so that Discord API does not get spammed and bans the bot + setTimeout(async () => { + // Removes the role from the user + if (!(member.roles.cache.has(IDs.roles.nonvegan.nonvegan) + || member.roles.cache.has(IDs.roles.vegan.vegan))) { + await member.roles.remove(IDs.roles.verifyingAsVegan); + await member.roles.add(IDs.roles.nonvegan.nonvegan); + await interaction.editReply(`Processed ${i + 1}/${verVeganLength} users\nEstimate time to completion: ${calcETA(apiTimeout, i, verVeganLength)}`); + } + }, apiTimeout * i); + } + + // Set the timeout for the completion + setTimeout( + async () => { + await interaction.editReply(`Successfully gave all ${getVerVegan!.name} users the ${getNotVegan!.name} role!`); + }, + apiTimeout * verVeganLength, + ); + } +} diff --git a/src/preconditions/VerifierCoordinatorOnly.ts b/src/preconditions/VerifierCoordinatorOnly.ts new file mode 100644 index 0000000..16fb625 --- /dev/null +++ b/src/preconditions/VerifierCoordinatorOnly.ts @@ -0,0 +1,52 @@ +// 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 { AllFlowsPrecondition } from '@sapphire/framework'; +import type { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'; +import { IDs } from '../utils/ids'; +import type { GuildMember } from 'discord.js'; + +export class VerifierCoordinatorOnlyPrecondition extends AllFlowsPrecondition { + public override async messageRun(message: Message) { + // for message command + return this.checkVerifierCoordinator(message.member!); + } + + public override async chatInputRun(interaction: CommandInteraction) { + // for slash command + return this.checkVerifierCoordinator(interaction.member! as GuildMember); + } + + public override async contextMenuRun(interaction: ContextMenuInteraction) { + // for context menu command + return this.checkVerifierCoordinator(interaction.member! as GuildMember); + } + + private async checkVerifierCoordinator(user: GuildMember) { + return user.roles.cache.has(IDs.roles.staff.verifierCoordinator) + ? this.ok() + : this.error({ message: 'Only verifier coordinators can run this command!' }); + } +} + +declare module '@sapphire/framework' { + interface Preconditions { + VerifierCoordinatorOnly: never; + } +} diff --git a/src/utils/ids.ts b/src/utils/ids.ts index e80fec7..80e87e7 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -42,12 +42,14 @@ const IDs = { coordinator: '993636242019323904', devCoordinator: '966031741099855973', mentorCoordinator: '947905630939807785', + verifierCoordinator: '940721280376778822', restricted: '851624392928264222', moderator: '826157475815489598', verifier: '871802735031373856', }, patron: '765370219207852055', patreon: '993848684640997406', + verifyingAsVegan: '854725899576279060', }, channels: { staff: {