diff --git a/src/config/forms.ts b/src/config/forms.ts new file mode 100644 index 0000000..ff1dfb9 --- /dev/null +++ b/src/config/forms.ts @@ -0,0 +1,22 @@ +/** + * @copyright NHCarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +/* eslint-disable @typescript-eslint/naming-convention -- We need number keys. */ + +export const formIds: Record = { + 747: "Sanction Appeals", + 752: "Commission Request", + 753: "Contact Request", + 754: "Event Request", + 755: "Meeting Request", + 756: "Mentorship Request", + 757: "Staff Application", + 758: "Testimonial", + 764: "ASCII Submission", + 767: "Contributor Application", + 786: "Guild Wars Officer Application", + +}; diff --git a/src/config/ids.ts b/src/config/ids.ts index df7c582..d8ca8d5 100644 --- a/src/config/ids.ts +++ b/src/config/ids.ts @@ -6,6 +6,7 @@ export const ids = { channels: { + formSubmissions: "1410435042898874471", mentorshipGoalForum: "1400629118110011526", mentorshipProjectForum: "1400616702265266186", naomiDiscussionForum: "1408154690121633917", diff --git a/src/index.ts b/src/index.ts index 1faa3c4..d928788 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,9 +4,14 @@ * @author Naomi Carrigan */ -import { Client, GatewayIntentBits, Events, Partials } from "discord.js"; +import { Client, + GatewayIntentBits, + Events, + Partials, + MessageFlags } from "discord.js"; import { scheduleJob } from "node-schedule"; import { App } from "octokit"; +import { ids } from "./config/ids.js"; import { handleMessageCreate } from "./events/handleMessageCreate.js"; import { cacheData } from "./modules/cacheData.js"; import { @@ -72,8 +77,21 @@ amari.discord.on(Events.MessageCreate, (message) => { amari.discord.on(Events.InteractionCreate, (interaction) => { if (interaction.isButton() && interaction.customId === "resolve") { - void interaction.message.delete(); + if (interaction.user.id !== ids.users.naomi) { + return void interaction.reply( + { content: "Who are you????", + flags: [ MessageFlags.Ephemeral ] }, + ); + } + return void interaction.message.delete(); } + if (interaction.isAutocomplete()) { + return void interaction; + } + return void interaction.reply({ + content: "What?", + flags: [ MessageFlags.Ephemeral ], + }); }); amari.discord.on(Events.UserUpdate, (_oldUser, updatedUser) => { diff --git a/src/interfaces/formSubmission.ts b/src/interfaces/formSubmission.ts new file mode 100644 index 0000000..d7eeb89 --- /dev/null +++ b/src/interfaces/formSubmission.ts @@ -0,0 +1,12 @@ +/** + * @copyright NHCarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +/* eslint-disable @typescript-eslint/naming-convention -- Baserow uses snake case */ + +export interface FormSubmission { + table_id: number; + items: Array<{ id: number }>; +} diff --git a/src/modules/processFormSubmission.ts b/src/modules/processFormSubmission.ts new file mode 100644 index 0000000..88d8009 --- /dev/null +++ b/src/modules/processFormSubmission.ts @@ -0,0 +1,70 @@ +/** + * @copyright NHCarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { MessageFlags } from "discord.js"; +import { formIds } from "../config/forms.js"; +import { ids } from "../config/ids.js"; +import { logger } from "../utils/logger.js"; +import type { Amari } from "../interfaces/amari.js"; +import type { FormSubmission } from "../interfaces/formSubmission.js"; +import type { FastifyRequest, FastifyReply } from "fastify"; + +/** + * Logs when a form is submitted through our Baserow instance. + * @param amari - Amari's intance. + * @param request - The fastify request payload. + * @param response - The fastify reply class. + */ +export const processFormSubmission = async( + amari: Amari, + // eslint-disable-next-line @typescript-eslint/naming-convention -- Fastify standard. + request: FastifyRequest<{ Body: FormSubmission }>, + response: FastifyReply, +): Promise => { + const { secret } = request.headers; + if (secret !== process.env.BASEROW_SECRET + || process.env.BASEROW_SECRET === undefined) { + await response.status(403).send({ message: "Invalid Secret Provided." }); + return; + } + await response.status(204).send(); + const channel = amari.discord.channels.cache.get(ids.channels.formSubmissions) + ?? await amari.discord.channels.fetch(ids.channels.formSubmissions); + if (channel?.isSendable() !== true) { + await logger.log( + "warn", + "Form submission channel does not exist or is not sendable.", + ); + return; + } + const { table_id: table, items } = request.body; + const rowIds = items.map((item) => { + return item.id; + }).join(", "); + const tableName = formIds[table]; + await channel.send({ + components: [ + { + content: `${tableName ?? "Unknown Form"} Submission Received!\n\nRow ID(s): ${rowIds}`, + type: 10, + }, + { + components: [ + { + // eslint-disable-next-line @typescript-eslint/naming-convention -- Requirement for Discord. + custom_id: "resolve", + disabled: false, + label: "Confirm", + style: 3, + type: 2, + }, + ], + type: 1, + }, + ], + flags: [ MessageFlags.IsComponentsV2 ], + }); +}; diff --git a/src/server/serve.ts b/src/server/serve.ts index ed135d9..403b0dc 100644 --- a/src/server/serve.ts +++ b/src/server/serve.ts @@ -5,9 +5,11 @@ */ import fastify from "fastify"; +import { processFormSubmission } from "../modules/processFormSubmission.js"; import { processGithubEvent } from "../modules/processGitHubEvent.js"; import { logger } from "../utils/logger.js"; import type { Amari } from "../interfaces/amari.js"; +import type { FormSubmission } from "../interfaces/formSubmission.js"; import type { GithubPayload } from "../interfaces/github.js"; const html = ` @@ -79,6 +81,19 @@ export const instantiateServer = (amari: Amari): void => { } }); + server. + // eslint-disable-next-line @typescript-eslint/naming-convention -- Fastify standard. + post<{ Body: FormSubmission }>("/form", async(request, response) => { + try { + await processFormSubmission(amari, request, response); + } catch (error) { + if (!(error instanceof Error)) { + return; + } + await logger.error("/form route", error); + } + }); + server.listen({ port: 7044 }, (error) => { if (error) { void logger.error("instantiate server", error);