From b1196158a57cb7e186d9e6704b8d7b3207a333d9 Mon Sep 17 00:00:00 2001 From: Hikari Date: Mon, 2 Mar 2026 15:55:19 -0800 Subject: [PATCH] feat: deduplicate mentee welcome messages Track welcomed mentees in data/welcomed.txt to prevent sending the onboarding message multiple times if the mentorship role is re-assigned. --- .gitignore | 3 ++- data/.gitkeep | 0 src/modules/processMentorshipRole.ts | 6 ++++++ src/utils/welcomedMentees.ts | 30 ++++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 data/.gitkeep create mode 100644 src/utils/welcomedMentees.ts diff --git a/.gitignore b/.gitignore index aab8b24..45cf57a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -prod \ No newline at end of file +prod +data/welcomed.txt \ No newline at end of file diff --git a/data/.gitkeep b/data/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/processMentorshipRole.ts b/src/modules/processMentorshipRole.ts index 97124eb..d65277c 100644 --- a/src/modules/processMentorshipRole.ts +++ b/src/modules/processMentorshipRole.ts @@ -6,6 +6,10 @@ import { ids } from "../config/ids.js"; import { logger } from "../utils/logger.js"; +import { + addWelcomedMentee, + welcomedMentees, +} from "../utils/welcomedMentees.js"; import type { Amari } from "../interfaces/amari.js"; import type { GuildMember, PartialGuildMember } from "discord.js"; @@ -25,6 +29,7 @@ export const processMentorshipRole = async( if ( oldMember.roles.cache.has(ids.roles.mentorship) || !updatedMember.roles.cache.has(ids.roles.mentorship) + || welcomedMentees.has(updatedMember.id) ) { return; } @@ -52,6 +57,7 @@ Last name: \`\`\` Then read our [mentorship wiki]() for the next steps!`, }); + addWelcomedMentee(updatedMember.id); await logger.metric("processed_mentorship_role", 1, { user: updatedMember.id, }); diff --git a/src/utils/welcomedMentees.ts b/src/utils/welcomedMentees.ts new file mode 100644 index 0000000..8b18a63 --- /dev/null +++ b/src/utils/welcomedMentees.ts @@ -0,0 +1,30 @@ +/** + * @copyright NHCarrigan + * @license Naomi's Public License + * @author Naomi Carrigan + */ + +import { appendFileSync, existsSync, readFileSync } from "node:fs"; + +const filePath = "data/welcomed.txt"; + +const loadWelcomedMentees = (): Set => { + if (!existsSync(filePath)) { + return new Set(); + } + const contents = readFileSync(filePath, "utf-8"); + return new Set(contents.split("\n").filter(Boolean)); +}; + +const welcomedMentees = loadWelcomedMentees(); + +/** + * Appends a mentee's ID to the welcomed set and persists it to disk. + * @param id - The Discord user ID to record. + */ +const addWelcomedMentee = (id: string): void => { + welcomedMentees.add(id); + appendFileSync(filePath, `${id}\n`); +}; + +export { addWelcomedMentee, welcomedMentees };