From 82c7814b5e21a942090cc47bc92c28b0f699096d Mon Sep 17 00:00:00 2001 From: ray Date: Fri, 11 Apr 2025 01:57:26 -0400 Subject: [PATCH] feat: add alerting infrastructure and hack knight alerts --- src/alerts/attendance.ts | 23 +++++++++++++++++++++++ src/alerts/hack_night_setup.ts | 22 ++++++++++++++++++++++ src/alerts/index.ts | 4 ++++ src/index.ts | 34 ++++++++++++++++++++++++++++++++++ src/utils/consts.ts | 8 +++++++- 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/alerts/attendance.ts create mode 100644 src/alerts/hack_night_setup.ts create mode 100644 src/alerts/index.ts diff --git a/src/alerts/attendance.ts b/src/alerts/attendance.ts new file mode 100644 index 0000000..dcbecc6 --- /dev/null +++ b/src/alerts/attendance.ts @@ -0,0 +1,23 @@ +import { type Client, Colors, EmbedBuilder } from "discord.js"; +import { + ATTENDANCE_CHANNEL_ID, + KNIGHT_ROLE_ID, + PROJECT_HACK_NIGHT_CHANNEL_ID, +} from "../utils/consts"; + +export default { + name: "attendance", + description: "Hourly attendance checks during Hack Night", + channel: PROJECT_HACK_NIGHT_CHANNEL_ID, + embed: (client: Client) => + new EmbedBuilder() + .setColor(Colors.DarkOrange) + .setTitle("⏰ REMINDER: Hack Night Attendance Check") + .setDescription( + `<@${KNIGHT_ROLE_ID}> please do an attendance run and post the results in <#${ATTENDANCE_CHANNEL_ID}>!\n\nConfirm this has been done by reacting with a ✅ to this message.`, + ), + crons: [ + "0 21-23 * * 5", // At minute 0 past every hour from 21 through 23 on Friday. + "0 0-2 * * 6", // At minute 0 past every hour from 0 through 2 on Saturday. + ], +}; diff --git a/src/alerts/hack_night_setup.ts b/src/alerts/hack_night_setup.ts new file mode 100644 index 0000000..b99547f --- /dev/null +++ b/src/alerts/hack_night_setup.ts @@ -0,0 +1,22 @@ +import { type Client, Colors, EmbedBuilder } from "discord.js"; +import { + ATTENDANCE_CHANNEL_ID, + KNIGHT_ROLE_ID, + PROJECT_HACK_NIGHT_CHANNEL_ID, +} from "../utils/consts"; + +export default { + name: "hack_night_setup", + description: "Setting up for Hack Night", + channel: PROJECT_HACK_NIGHT_CHANNEL_ID, + embed: (client: Client) => + new EmbedBuilder() + .setColor(Colors.DarkOrange) + .setTitle("⏰ REMINDER: Set Up Hack Night") + .setDescription( + `<@${KNIGHT_ROLE_ID}> it's time to setup Hack Night! Make sure somebody is responsible for bringing the Hack Cart to Bechtel and setting up all the devices.\n\nRefer to https://puhack.horse/hn-setup for the checklist of things to do!\n\nConfirm this has been done by reacting with a ✅ to this message.`, + ), + crons: [ + "45 19 * * 5", // At 19:45 on Friday. + ], +}; diff --git a/src/alerts/index.ts b/src/alerts/index.ts new file mode 100644 index 0000000..8d49d71 --- /dev/null +++ b/src/alerts/index.ts @@ -0,0 +1,4 @@ +import attendance from "./attendance"; +import hack_night_setup from "./hack_night_setup"; + +export { attendance, hack_night_setup }; diff --git a/src/index.ts b/src/index.ts index 5f8a4c5..b079187 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,9 +9,11 @@ import { } from "discord.js"; import cron from "node-cron"; +import * as alerts from "./alerts"; import { commands } from "./commands"; import { messageCreate } from "./events"; +// TODO(rayhanadev): convert these into alerts import { checkBirthdays } from "./utils/birthdays"; import { createHackNightImagesThread, @@ -76,6 +78,36 @@ client.on(Events.InteractionCreate, async (interaction) => { } }); +const alertCronHandlers: cron.ScheduledTask[] = []; + +for (const alert of Object.values(alerts)) { + console.log(`Setting up alert: \`${alert.name}\` - ${alert.description}`); + for (const schedule of alert.crons) { + console.log(` - ${schedule}`); + const handler = cron.schedule(schedule, async () => { + const channel = await client.channels.fetch(alert.channel); + if (!channel?.isTextBased() || !channel.isSendable()) { + console.error( + `Channel ${alert.channel} is not a text channel, skipping alert`, + ); + return; + } + + const message = await alert.embed(client); + if (!message) { + console.error(`Failed to create alert: ${alert.name}`); + return; + } + + await channel.send({ + embeds: [message], + }); + }); + + alertCronHandlers.push(handler); + } +} + const checkBirthdaysTask = cron.schedule("1 0 * * *", checkBirthdays(client)); const createHackNightImagesThreadTask = cron.schedule( "0 20 * * 5", @@ -97,6 +129,8 @@ client.on(Events.ClientReady, (event) => { checkBirthdaysTask.start(); createHackNightImagesThreadTask.start(); cleanupHackNightImagesThreadTask.start(); + + alertCronHandlers.forEach((handler) => handler.start()); }); client.on(messageCreate.eventType, async (message) => { diff --git a/src/utils/consts.ts b/src/utils/consts.ts index ef9f811..636802d 100644 --- a/src/utils/consts.ts +++ b/src/utils/consts.ts @@ -1,7 +1,13 @@ +export const ADMINS = ["636701123620634653"]; + export const LOUNGE_CHANNEL_ID = "809628073896443904"; export const HACK_NIGHT_CHANNEL_ID = "1020777328172859412"; -export const ADMINS = ["636701123620634653"]; +export const PROJECT_HACK_NIGHT_CHANNEL_ID = "1015596235685646357"; +export const ATTENDANCE_CHANNEL_ID = "1287861645628149760"; + export const ORGANIZER_ROLE_ID = "1012751663322382438"; +export const KNIGHT_ROLE_ID = "1183270835469963354"; export const BISHOP_ROLE_ID = "1199891815780847647"; export const HACK_NIGHT_PHOTOGRAPHY_AWARD_ROLE_ID = "1340775295233560606"; + export const EVERGREEN_CREATE_ISSUE_STRING = "evergreen it";