Skip to content

Commit

Permalink
Merge pull request #10 from datasektionen/feat/nv/verify-slash-command
Browse files Browse the repository at this point in the history
feat(verify): add new command
  • Loading branch information
niklasvatn committed Aug 21, 2022
2 parents 072d8c6 + 3abcdf0 commit 4dc7245
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/commands/add/add.handler.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ChatInputCommandInteraction } from "discord.js";

export const handleAdd = (interaction: ChatInputCommandInteraction) => {
export const handleAdd = async (interaction: ChatInputCommandInteraction) => {
const { options } = interaction;
const num1 = options.getNumber("num1", true);
const num2 = options.getNumber("num2", true);

interaction.reply({
await interaction.reply({
content: `The sum of the two numbers is: ${num1 + num2}`,
ephemeral: true,
});
Expand Down
4 changes: 2 additions & 2 deletions src/commands/ping/ping.handler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CommandInteraction } from "discord.js";

export const handlePing = (interaction: CommandInteraction) => {
interaction.reply({
export const handlePing = async (interaction: CommandInteraction) => {
await interaction.reply({
content: "pong",
ephemeral: true,
});
Expand Down
8 changes: 6 additions & 2 deletions src/commands/register_commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { handleAdd } from "./add/add.handler";
import { commands } from "./commands";
import { CommandNames } from "./command.names";
import { handlePing } from "./ping/ping.handler";
import { handleVerify } from "./verify/verify.handler";

export const register_commands = async () => {
const guild = await getGuild();
Expand All @@ -15,10 +16,13 @@ export const register_commands = async () => {
}
switch (interaction.commandName) {
case CommandNames.PING:
handlePing(interaction);
await handlePing(interaction);
break;
case CommandNames.ADD:
handleAdd(interaction);
await handleAdd(interaction);
break;
case CommandNames.VERIFY:
await handleVerify(interaction);
break;
}
});
Expand Down
7 changes: 7 additions & 0 deletions src/commands/verify/subcommands/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Message } from "discord.js";

export const isKthEmail = (messageText: string) =>
new RegExp(/^[a-zA-Z0-9]+@kth[.]se$/).test(messageText);

export const messageIsToken = (messageText: string) =>
messageText.match(/^[a-zA-Z0-9_-]+$/);
39 changes: 39 additions & 0 deletions src/commands/verify/subcommands/verify_begin.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ChatInputCommandInteraction, CommandInteraction } from "discord.js";
import { token_discord, token_email } from "../../../database_config";
import { generateToken } from "../../../utils/generate_token";
import { sendMail } from "../../../utils/mail";
import { isKthEmail } from "./util";

export const handleVerifyBegin = async (
interaction: ChatInputCommandInteraction
) => {
const { user, options } = interaction;
const messageText = options.getString("email", true);
if (!isKthEmail(messageText)) {
await interaction.reply({
content: "Please, enter a valid KTH email address.",
ephemeral: true,
});
return;
}

const token = generateToken(parseInt(process.env.TOKEN_SIZE as string));
const timeout = parseInt(process.env.TOKEN_TIMEOUT as string);
await token_discord.set(token, user.id, timeout);
await token_email.set(token, messageText, timeout);

try {
const result = await sendMail(messageText, token);
console.log(`Email sent, received response: ${JSON.stringify(result)}`);
} catch (error) {
console.error(error);
await interaction.reply({
content: "Something went wrong, please try again.",
ephemeral: true,
});
}
await interaction.reply({
content: `Verification email sent, check ${messageText} for your verification code.`,
ephemeral: true,
});
};
4 changes: 4 additions & 0 deletions src/commands/verify/subcommands/verify_command.names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export enum VerifyCommandNames {
BEGIN = "begin",
SUBMIT = "submit",
}
54 changes: 54 additions & 0 deletions src/commands/verify/subcommands/verify_submit.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ChatInputCommandInteraction } from "discord.js";
import {
token_discord,
token_email,
verified_users,
} from "../../../database_config";
import { setN0llanRole, setRoleVerified } from "../../../utils/roles";
import { messageIsToken } from "./util";

export const handleVerifySubmit = async (
interaction: ChatInputCommandInteraction
) => {
const { user, options } = interaction;
const messageText = options.getString("verification-code", true);

if (!messageIsToken(messageText)) {
await interaction.reply({
content: "Not a valid code",
ephemeral: true,
});
return;
}

const [discordId, emailAddress] = await Promise.all([
token_discord.get(messageText) as Promise<string | undefined>,
token_email.get(messageText) as Promise<string | undefined>,
]);

if (!emailAddress || !discordId || discordId !== user.id) {
await interaction.reply({
content:
"Verification unsuccessful, submit the code again or request a new code.",
ephemeral: true,
});
return;
}

verified_users.set(discordId, emailAddress);
try {
await setRoleVerified(user);
await interaction.reply({
content: `Du är nu verifierad. Dubbelkolla att du har blivit tilldelad @**${process.env.DISCORD_VERIFIED_ROLE}** rollen!`,
ephemeral: true,
});
// setN0llanRole(user, emailAddress.split("@")[0]);
} catch (error) {
console.error(error);
await interaction.reply({
content: "Something went wrong, please try again.",
ephemeral: true,
});
}
return;
};
33 changes: 33 additions & 0 deletions src/commands/verify/verify.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { SlashCommandBuilder } from "discord.js";
import { CommandNames } from "../command.names";
import { VerifyCommandNames } from "./subcommands/verify_command.names";

export const verifyCommand = new SlashCommandBuilder()
.setName(CommandNames.VERIFY)
.setDescription(
"Automatically verifies that you are a kth student via @kth.se email"
);

verifyCommand.addSubcommand((subcommand) =>
subcommand
.setName(VerifyCommandNames.BEGIN)
.setDescription("Enter your @kth.se address to receive a verification code")
.addStringOption((option) =>
option
.setName("email")
.setDescription("Your @kth address")
.setRequired(true)
)
);

verifyCommand.addSubcommand((subcommand) =>
subcommand
.setName(VerifyCommandNames.SUBMIT)
.setDescription("Verifies you with the code sent to your email")
.addStringOption((option) =>
option
.setName("verification-code")
.setDescription("The code sent to your email address")
.setRequired(true)
)
);
19 changes: 19 additions & 0 deletions src/commands/verify/verify.handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ChatInputCommandInteraction, CommandInteraction } from "discord.js";
import { handleVerifyBegin } from "./subcommands/verify_begin.handler";
import { VerifyCommandNames } from "./subcommands/verify_command.names";
import { handleVerifySubmit } from "./subcommands/verify_submit.handler";

export const handleVerify = async (
interaction: ChatInputCommandInteraction
) => {
const subCommandName = interaction.options.getSubcommand(true);

switch (subCommandName) {
case VerifyCommandNames.BEGIN:
await handleVerifyBegin(interaction);
break;
case VerifyCommandNames.SUBMIT:
await handleVerifySubmit(interaction);
break;
}
};
30 changes: 7 additions & 23 deletions src/messages/on_dm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { token_discord, token_email, verified_users } from "../database_config";
import { sendMail } from "../utils/mail";
import { Message } from "discord.js";
import { generateToken } from "../utils/generate_token";
import {
isKthEmail,
messageIsToken,
} from "../commands/verify/subcommands/util";

export async function onDM(message: Message, messageText: string) {
if (isKthEmail(messageText)) {
Expand All @@ -25,11 +29,11 @@ export async function onDM(message: Message, messageText: string) {

if (messageIsToken(messageText)) {
const [discordId, emailAddress] = await Promise.all([
token_discord.get(messageText),
token_email.get(messageText),
token_discord.get(messageText) as Promise<string>,
token_email.get(messageText) as Promise<string>,
]);

if (emailAndDiscordIdIsCorrect(message, emailAddress, discordId)) {
if (emailAddress && discordId && discordId !== message.author.id) {
verified_users.set(discordId, emailAddress);
try {
await setRoleVerified(message.author);
Expand Down Expand Up @@ -58,23 +62,3 @@ export async function onDM(message: Message, messageText: string) {
)
.catch((err) => console.error(err));
}

function isKthEmail(messageText: string) {
return new RegExp(/^[a-zA-Z0-9]+@kth[.]se$/).test(messageText);
}

function messageIsToken(messageText: string) {
return messageText.match(/^[a-zA-Z0-9_-]+$/);
}

function emailAndDiscordIdIsCorrect(
message: Message,
email_address: string,
discord_id: string
) {
return (
email_address &&
discord_id &&
discord_id.toString() === message.author.id.toString()
);
}

0 comments on commit 4dc7245

Please sign in to comment.