diff --git a/package-lock.json b/package-lock.json index 7865267..e40299a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "arabot", - "version": "0.1.0", + "version": "0.2.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "arabot", - "version": "0.1.0", + "version": "0.2.3", "license": "GPL-3.0-or-later", "dependencies": { "@prisma/client": "^4.10.1", diff --git a/package.json b/package.json index 6a701a6..25e2482 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "arabot", - "version": "0.2.1", + "version": "0.2.3", "description": "A Discord bot for Animal Rights Advocates", "main": "dist/index.js", "scripts": { diff --git a/prisma/migrations/20230220123804_verify_manual/migration.sql b/prisma/migrations/20230220123804_verify_manual/migration.sql new file mode 100644 index 0000000..7f5aecd --- /dev/null +++ b/prisma/migrations/20230220123804_verify_manual/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Verify" ADD COLUMN "manual" BOOLEAN NOT NULL DEFAULT false; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index cbcc447..ec44198 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -66,6 +66,7 @@ model Verify { joinTime DateTime @default(now()) startTime DateTime? finishTime DateTime? + manual Boolean @default(false) // If they were verified with the verify command timedOut Boolean @default(false) // If they got kicked out of verification because they timed out //complete Boolean @default(false) // If the verification was incomplete // Roles they got from verification diff --git a/src/commands/mod/restriction/unrestrict.ts b/src/commands/mod/restriction/unrestrict.ts index eef445f..42c3d86 100644 --- a/src/commands/mod/restriction/unrestrict.ts +++ b/src/commands/mod/restriction/unrestrict.ts @@ -173,9 +173,6 @@ export class UnRestrictCommand extends Command { if (await checkActive(userId)) { const roles = await fetchRoles(userId); - if (roles.includes(IDs.roles.vegan.vegan)) { - roles.push(IDs.roles.vegan.nvAccess); - } await member.roles.add(roles); // Unrestricts the user on the database await unRestrict(userId, modId); diff --git a/src/commands/roles/activist.ts b/src/commands/roles/verification/activist.ts similarity index 100% rename from src/commands/roles/activist.ts rename to src/commands/roles/verification/activist.ts diff --git a/src/commands/roles/convinced.ts b/src/commands/roles/verification/convinced.ts similarity index 100% rename from src/commands/roles/convinced.ts rename to src/commands/roles/verification/convinced.ts diff --git a/src/commands/roles/plus.ts b/src/commands/roles/verification/plus.ts similarity index 100% rename from src/commands/roles/plus.ts rename to src/commands/roles/verification/plus.ts diff --git a/src/commands/roles/trusted.ts b/src/commands/roles/verification/trusted.ts similarity index 100% rename from src/commands/roles/trusted.ts rename to src/commands/roles/verification/trusted.ts diff --git a/src/commands/roles/vegan.ts b/src/commands/roles/verification/vegan.ts similarity index 100% rename from src/commands/roles/vegan.ts rename to src/commands/roles/verification/vegan.ts diff --git a/src/commands/roles/vegcurious.ts b/src/commands/roles/verification/vegcurious.ts similarity index 100% rename from src/commands/roles/vegcurious.ts rename to src/commands/roles/verification/vegcurious.ts diff --git a/src/commands/verification/verify.ts b/src/commands/verification/verify.ts new file mode 100644 index 0000000..517740f --- /dev/null +++ b/src/commands/verification/verify.ts @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +/* + Animal Rights Advocates Discord Bot + Copyright (C) 2023 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 { Args, Command, RegisterBehavior } from '@sapphire/framework'; +import type { + Message, + User, + Guild, + Snowflake, +} from 'discord.js'; +import IDs from '#utils/ids'; +import { finishVerifyMessages, giveVerificationRoles } from '#utils/verification'; +import { manualVerification } from '#utils/database/verification'; + +export class VerifyCommand extends Command { + public constructor(context: Command.Context, options: Command.Options) { + super(context, { + ...options, + name: 'verify', + aliases: ['ver'], + description: 'Gives roles to the user', + preconditions: [['ModCoordinatorOnly', 'VerifierCoordinatorOnly', 'VerifierOnly']], + }); + } + + // Registers that this is a slash command + public override registerApplicationCommands(registry: Command.Registry) { + registry.registerChatInputCommand( + (builder) => builder + .setName(this.name) + .setDescription(this.description) + .addUserOption((option) => option.setName('user') + .setDescription('User to give the roles to') + .setRequired(true)) + .addStringOption((option) => option.setName('roles') + .setDescription('Roles to give to the user') + .setRequired(true)), + { + behaviorWhenNotIdentical: RegisterBehavior.Overwrite, + }, + ); + } + + // Command run + public async chatInputRun(interaction: Command.ChatInputCommandInteraction) { + // Get the arguments + const user = interaction.options.getUser('user', true); + const roles = interaction.options.getString('roles', true); + const verifier = interaction.member; + const { guild } = interaction; + const messageId = interaction.id; + + // Checks if all the variables are of the right type + if (verifier === null || guild === null) { + await interaction.reply({ + content: 'Error fetching moderator or guild!', + ephemeral: true, + fetchReply: true, + }); + return; + } + + const verify = await this.verify(user, verifier.user.id, roles, messageId, guild); + + await interaction.reply({ + content: verify.message, + fetchReply: true, + }); + } + + public async messageRun(message: Message, args: Args) { + // Get arguments + let user: User; + try { + user = await args.pick('user'); + } catch { + await message.react('❌'); + await message.reply('User was not provided!'); + return; + } + + const roles = args.finished ? null : await args.rest('string'); + + if (roles === null) { + await message.react('❌'); + await message.reply('Roles were not provided!'); + return; + } + + const verifier = message.member; + + if (verifier === null) { + await message.react('❌'); + await message.reply('Verifier not found! Try again or contact a developer!'); + return; + } + + const { guild } = message; + + if (guild === null) { + await message.react('❌'); + await message.reply('Guild not found! Try again or contact a developer!'); + return; + } + + const verify = await this.verify(user, verifier.user.id, roles, message.id, guild); + + await message.reply(verify.message); + await message.react(verify.success ? '✅' : '❌'); + } + + private async verify( + user: User, + verifierId: Snowflake, + rolesString: string, + messageId: Snowflake, + guild: Guild, + ) { + const info = { + message: '', + success: false, + }; + + const roles = { + vegan: false, + activist: false, + araVegan: false, + trusted: false, + vegCurious: false, + convinced: false, + }; + + let member = guild.members.cache.get(user.id); + + // Checks if member is null + if (member === undefined) { + member = await guild.members.fetch(user.id) + .catch(() => undefined); + if (member === undefined) { + info.message = 'Failed to fetch member'; + return info; + } + } + + if (member.roles.cache.hasAny(...IDs.roles.restrictions.restricted)) { + info.message = 'Can\'t verify a restricted user!'; + return info; + } + + let verifier = guild.members.cache.get(verifierId); + + // Checks if verifier is null + if (verifier === undefined) { + verifier = await guild.members.fetch(user.id) + .catch(() => undefined); + if (verifier === undefined) { + info.message = 'Failed to fetch verifier'; + return info; + } + } + + const roleArgs = rolesString.split(' '); + + roleArgs.forEach((role) => { + switch (role.toLowerCase()) { + case 'v': + roles.vegan = true; + break; + case 'a': + roles.activist = true; + break; + case 'x': + roles.araVegan = true; + break; + case 't': + roles.trusted = true; + break; + case 'nv': + break; + case 'veg': + roles.vegCurious = true; + break; + case 'conv': + roles.convinced = true; + break; + default: + info.message = 'There was an invalid argument!'; + break; + } + }); + + if (info.message.length > 0) { + return info; + } + + if ((roles.vegan || member.roles.cache.has(IDs.roles.vegan.vegan)) + && (roleArgs.includes('nv') || roles.vegCurious || roles.convinced)) { + info.message = 'Can\'t give non-vegan roles to a vegan'; + return info; + } + + if (roleArgs.includes('nv') + && (roles.vegan || roles.activist || roles.araVegan)) { + info.message = 'Can\'t give vegan roles to a non-vegan'; + return info; + } + + await giveVerificationRoles(member, roles, true); + + await finishVerifyMessages(user, roles, true); + + await manualVerification(messageId, member, verifier, roles); + + if (member.roles.cache.has(IDs.roles.nonvegan.nonvegan) + && (roles.vegan || roles.activist || roles.araVegan)) { + await member.roles.remove([ + IDs.roles.nonvegan.nonvegan, + IDs.roles.nonvegan.vegCurious, + IDs.roles.nonvegan.convinced, + ]); + } + + info.success = true; + info.message = `Verified ${user}`; + return info; + } +} diff --git a/src/listeners/rolesJoinServer.ts b/src/listeners/rolesJoinServer.ts index 8a04e5c..26bb424 100644 --- a/src/listeners/rolesJoinServer.ts +++ b/src/listeners/rolesJoinServer.ts @@ -37,10 +37,6 @@ export class RolesJoinServerListener extends Listener { const roles = await fetchRoles(member.id); - if (roles.includes(IDs.roles.vegan.vegan)) { - roles.push(IDs.roles.vegan.nvAccess); - } - // Check if the user is restricted if (await checkActive(member.id)) { const section = await getSection(member.id); diff --git a/src/listeners/verification/joinVC.ts b/src/listeners/verification/joinVC.ts index 1af6c45..b3c6ab0 100644 --- a/src/listeners/verification/joinVC.ts +++ b/src/listeners/verification/joinVC.ts @@ -26,7 +26,6 @@ import type { VoiceState, GuildMember, Guild, - User, } from 'discord.js'; import { time, @@ -38,7 +37,12 @@ import { ActionRowBuilder, EmbedBuilder, } from 'discord.js'; -import { createVerificationText, createVerificationVoice } from '#utils/verification'; +import { + createVerificationText, + createVerificationVoice, + giveVerificationRoles, + finishVerifyMessages, +} from '#utils/verification'; import { maxVCs, questionInfo, serverFind } from '#utils/verificationConfig'; import { joinVerification, startVerification, finishVerification } from '#utils/database/verification'; import { findNotes } from '#utils/database/sus'; @@ -122,6 +126,7 @@ export class VerificationJoinVCListener extends Listener { // Remove all roles from the user await member.roles.remove([ IDs.roles.vegan.vegan, + IDs.roles.vegan.nvAccess, IDs.roles.trusted, IDs.roles.nonvegan.nonvegan, IDs.roles.nonvegan.convinced, @@ -282,6 +287,7 @@ export class VerificationJoinVCListener extends Listener { roles: { vegan: false, activist: false, + araVegan: false, trusted: false, vegCurious: false, convinced: false, @@ -442,7 +448,7 @@ export class VerificationJoinVCListener extends Listener { // Add verification data to database await finishVerification(verId, button.user.id, info); // Give roles on Discord - await this.giveRoles(user, info.roles); + await giveVerificationRoles(user, info.roles); // Add timeout if they do not have activist role if (!info.roles.activist) { // @ts-ignore @@ -464,7 +470,7 @@ export class VerificationJoinVCListener extends Listener { components: [], }); // Send welcome message after verification - await this.finishMessages(user.user, info.roles); + await finishVerifyMessages(user.user, info.roles); } if (button.customId === 'cancel' && info.page >= questionLength) { info.page = 5; @@ -534,7 +540,7 @@ export class VerificationJoinVCListener extends Listener { } if (roles.vegan) { rolesText += `<@&${IDs.roles.vegan.vegan}>`; - rolesText += `<@&${IDs.roles.vegan.nvAccess}`; + rolesText += `<@&${IDs.roles.vegan.nvAccess}>`; } else { rolesText += `<@&${IDs.roles.nonvegan.nonvegan}>`; } @@ -549,121 +555,4 @@ export class VerificationJoinVCListener extends Listener { } 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); - rolesAdd.push(IDs.roles.vegan.nvAccess); - } else { - rolesAdd.push(IDs.roles.nonvegan.nonvegan); - } - if (roles.activist) { - rolesAdd.push(IDs.roles.vegan.activist); - } else { - rolesAdd.push(IDs.roles.verifyBlock); - } - if (roles.trusted) { - rolesAdd.push(IDs.roles.trusted); - } - if (roles.vegCurious) { - rolesAdd.push(IDs.roles.nonvegan.vegCurious); - } - 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 - }) { - // Send a DM with when their verification is finished - await this.finishDM(user, roles) - .catch(() => this.container.logger.error('Verification: Closed DMs')); - - // 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 user.send(activistMsg) - .catch(() => { 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); - } - } } diff --git a/src/utils/database/dbExistingUser.ts b/src/utils/database/dbExistingUser.ts index 0d5c5e9..0f3fecf 100644 --- a/src/utils/database/dbExistingUser.ts +++ b/src/utils/database/dbExistingUser.ts @@ -158,6 +158,7 @@ export async function fetchRoles(userId: Snowflake) { } if (roleQuery.vegan) { roles.push(IDs.roles.vegan.vegan); + roles.push(IDs.roles.vegan.nvAccess); } if (roleQuery.trusted) { roles.push(IDs.roles.trusted); diff --git a/src/utils/database/verification.ts b/src/utils/database/verification.ts index d1c11e8..83978c0 100644 --- a/src/utils/database/verification.ts +++ b/src/utils/database/verification.ts @@ -17,29 +17,70 @@ along with this program. If not, see . */ -import type { GuildMember } from 'discord.js'; +import type { GuildMember, Snowflake } from 'discord.js'; import { container } from '@sapphire/framework'; import { updateUser } from '#utils/database/dbExistingUser'; import { leaveBan } from '#utils/verificationConfig'; import { fibonacci } from '#utils/maths'; -export async function joinVerification(channelId: string, user: GuildMember) { +export async function manualVerification( + messageId: Snowflake, + member: GuildMember, + verifier: GuildMember, + roles: { + vegan: boolean, + activist: boolean, + araVegan: boolean, + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, +) { + await updateUser(member); + await updateUser(verifier); + + await container.database.verify.create({ + data: { + id: messageId, + user: { + connect: { + id: member.id, + }, + }, + verifier: { + connect: { + id: verifier.id, + }, + }, + manual: true, + // Roles + vegan: roles.vegan, + activist: roles.activist, + serverVegan: roles.araVegan, + trusted: roles.trusted, + vegCurious: roles.vegCurious, + convinced: roles.convinced, + }, + }); +} + +export async function joinVerification(channelId: Snowflake, member: GuildMember) { // Update the user on the database with the current roles they have - await updateUser(user); + await updateUser(member); await container.database.verify.create({ data: { id: channelId, user: { connect: { - id: user.id, + id: member.id, }, }, }, }); } -export async function startVerification(channelId: string) { +export async function startVerification(channelId: Snowflake) { await container.database.verify.update({ where: { id: channelId, @@ -50,7 +91,7 @@ export async function startVerification(channelId: string) { }); } -export async function getUser(channelId: string) { +export async function getUser(channelId: Snowflake) { // Get the snowflake of the user verifying const user = await container.database.verify.findUnique({ where: { @@ -71,8 +112,8 @@ export async function getUser(channelId: string) { } export async function finishVerification( - channelId: string, - verifierId: string, + channelId: Snowflake, + verifierId: Snowflake, info: { page: number, find: { @@ -86,6 +127,7 @@ export async function finishVerification( roles: { vegan: boolean, activist: boolean, + araVegan: boolean, trusted: boolean, vegCurious: boolean, convinced: boolean @@ -106,6 +148,7 @@ export async function finishVerification( // Roles vegan: info.roles.vegan, activist: info.roles.activist, + serverVegan: info.roles.araVegan, trusted: info.roles.trusted, vegCurious: info.roles.vegCurious, convinced: info.roles.convinced, @@ -121,7 +164,7 @@ export async function finishVerification( } // Checks if verification was complete -export async function checkFinish(channelId: string) { +export async function checkFinish(channelId: Snowflake) { // Get the snowflake of the user verifying const finish = await container.database.verify.findUnique({ where: { @@ -142,7 +185,7 @@ export async function checkFinish(channelId: string) { } // Counts how many times the user has not had a verifier join their VC before leaving -export async function countIncomplete(userId: string) { +export async function countIncomplete(userId: Snowflake) { // Count how many times the user has not completed a verification const incompleteCount = await container.database.verify.count({ where: { @@ -155,7 +198,7 @@ export async function countIncomplete(userId: string) { } // Gets the amount of time left on the block -export async function blockTime(userId: string) { +export async function blockTime(userId: Snowflake) { // Count how many times the user has not completed a verification const verification = await container.database.verify.findFirst({ where: { diff --git a/src/utils/devIDs.ts b/src/utils/devIDs.ts index b89f977..4fca68b 100644 --- a/src/utils/devIDs.ts +++ b/src/utils/devIDs.ts @@ -30,6 +30,7 @@ const devIDs = { activist: '999431675098447934', nvAccess: '1076859125415301141', plus: '999431675010359460', + araVegan: '999431674972618798', }, restrictions: { sus: '999431674997788673', diff --git a/src/utils/ids.ts b/src/utils/ids.ts index c69c51b..4118379 100644 --- a/src/utils/ids.ts +++ b/src/utils/ids.ts @@ -33,6 +33,7 @@ let IDs = { activist: '730915638746546257', nvAccess: '1076857105648209971', plus: '798682625619132428', + araVegan: '995394977658044506', }, restrictions: { sus: '859145930640457729', diff --git a/src/utils/verification.ts b/src/utils/verification.ts index e752249..7bd0541 100644 --- a/src/utils/verification.ts +++ b/src/utils/verification.ts @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later /* Animal Rights Advocates Discord Bot - Copyright (C) 2022 Anthony Berg + Copyright (C) 2023 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 @@ -17,11 +17,15 @@ along with this program. If not, see . */ +import { container } from '@sapphire/framework'; import { CategoryChannel, ChannelType, GuildMember, - PermissionsBitField, + PermissionsBitField, Snowflake, + TextChannel, + time, + User, VoiceBasedChannel, } from 'discord.js'; import IDs from '#utils/ids'; @@ -125,3 +129,135 @@ export async function createVerificationVoice( await channel.permissionOverwrites.edit(IDs.roles.vegan.vegan, { Connect: false }); } } + +export async function giveVerificationRoles( + member: GuildMember, + roles: { + vegan: boolean, + activist: boolean, + araVegan: boolean + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + manual: boolean = false, +) { + const rolesAdd: Snowflake[] = []; + if (roles.convinced) { + rolesAdd.push(IDs.roles.nonvegan.convinced); + } + if (roles.vegan) { + rolesAdd.push(IDs.roles.vegan.vegan); + rolesAdd.push(IDs.roles.vegan.nvAccess); + } else { + rolesAdd.push(IDs.roles.nonvegan.nonvegan); + } + if (roles.activist) { + rolesAdd.push(IDs.roles.vegan.activist); + } else if (!manual) { + rolesAdd.push(IDs.roles.verifyBlock); + } + if (roles.araVegan) { + rolesAdd.push(IDs.roles.vegan.araVegan); + } + if (roles.trusted) { + rolesAdd.push(IDs.roles.trusted); + } + if (roles.vegCurious) { + rolesAdd.push(IDs.roles.nonvegan.vegCurious); + } + await member.roles.add(rolesAdd); +} + +// Messages after verifying the user +export async function finishDM(user: User, roles: { + vegan: boolean, + activist: boolean, + araVegan: 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); + } +} + +// Messages after verifying the user +export async function finishVerifyMessages( + user: User, + roles: { + vegan: boolean, + activist: boolean, + araVegan: boolean + trusted: boolean, + vegCurious: boolean, + convinced: boolean + }, + manual: boolean = false, +) { + // Send a DM with when their verification is finished + if (!manual) { + await finishDM(user, roles) + .catch(() => container.logger.error('Verification: Closed DMs')); + } + + // Not vegan + if (!roles.vegan) { + const general = 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 = 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 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 user.send(activistMsg) + .catch(() => { + const activist = container.client.channels.cache + .get(IDs.channels.activism.activism) as TextChannel | undefined; + if (activist === undefined) { + return; + } + activist.send(activistMsg); + }); + } +}