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);
+ });
+ }
+}