From 6007a8bbfac47cfe9318541eede484c890489c6e Mon Sep 17 00:00:00 2001
From: jacob janzen <53062115+JacobJanzen@users.noreply.github.com>
Date: Wed, 11 Dec 2024 18:13:16 -0600
Subject: Complete refactor (#1)

---
 app.js | 211 +++++++++++++++++++++++++++--------------------------------------
 1 file changed, 86 insertions(+), 125 deletions(-)

(limited to 'app.js')

diff --git a/app.js b/app.js
index 705ad80..53fe461 100644
--- a/app.js
+++ b/app.js
@@ -1,130 +1,91 @@
-import 'dotenv/config';
-import express from 'express';
-import cron from 'node-cron';
+import "dotenv/config";
+import express from "express";
 import {
-  InteractionType,
-  InteractionResponseType,
-  verifyKeyMiddleware,
-} from 'discord-interactions';
-import { Client, GatewayIntentBits, ActivityType } from 'discord.js';
-import fs from 'node:fs';
-import { v4 as uuidv4 } from 'uuid';
-
-const client = new Client ({ intents: [GatewayIntentBits.Guilds] });
-var jobs = {};
-const job_crons = {};
-client.on('ready', () => {
-    console.log(`Logged in as ${client.user.tag}!`);
-    fs.readFile('jobs.json', 'utf8', (err,data) => {
-        jobs = err ? {} : JSON.parse(data);
-
-        Object.keys(jobs).forEach((job) => {
-            job_crons[job] = cron.schedule(jobs[job].crontab, () => {
-                client.channels.cache.get(jobs[job].channel_id).send(jobs[job].message);
-            }, {
-                scheduled: true,
-                timezone: process.env.TIMEZONE
-            });
+    InteractionType,
+    InteractionResponseType,
+    verifyKeyMiddleware,
+} from "discord-interactions";
+import { Client, GatewayIntentBits, ActivityType } from "discord.js";
+import { pet, schedule_message, unschedule_message } from "./command_impls.js";
+import { MessageSchedule } from "./message-scheduler.js";
+
+class State {
+    constructor() {
+        this.job_db = "jobs.json";
+        this.client = new Client({ intents: [GatewayIntentBits.Guilds] });
+    }
+}
+
+function handle_application_command(state, data, channel_id) {
+    const { name, options } = data;
+
+    switch (name) {
+        case "schedule_message":
+            return schedule_message(
+                state,
+                options[0].value,
+                channel_id,
+                options[1].value,
+            );
+
+        case "unschedule_message":
+            return unschedule_message(state, options[0].value);
+
+        case "pet":
+            return pet(state);
+
+        default:
+            console.error(`unknown command: ${name}`);
+            return res.status(400).json({ error: "unknown command" });
+    }
+}
+
+function main() {
+    const state = new State();
+
+    state.client.on("ready", () => {
+        console.log(`Logged in as ${state.client.user.tag}!`);
+        state.schedule = new MessageSchedule(state);
+        state.client.user.setPresence({
+            activities: [
+                {
+                    name: "sily",
+                    type: ActivityType.Playing,
+                },
+            ],
+            status: "idle",
         });
     });
-    client.user.setPresence({
-        activities: [{
-            name: 'sily',
-            type: ActivityType.Playing,
-        }],
-        status: "idle"
-    });
-});
-
-client.login(process.env.DISCORD_TOKEN);
-
-const app = express();
-const PORT = process.env.PORT || 3000;
-
-app.post('/', verifyKeyMiddleware(process.env.PUBLIC_KEY), async function (req, res) {
-  const { type, data } = req.body;
-
-  if (type === InteractionType.PING) {
-    return res.send({ type: InteractionResponseType.PONG });
-  }
-
-  if (type === InteractionType.APPLICATION_COMMAND) {
-      const { name, options, guild_id } = data;
-
-      if (name === 'schedule_message') {
-          const message = options[0].value;
-          const crontab = options[1].value;
-          const valid = cron.validate(crontab);
-          const id = uuidv4();
 
-          const content = valid ? `registered message: "${message}" with cron: "${crontab}" and id: "${id}"` : 'invalid cron';
-
-          if (valid) {
-              jobs[id] = {
-                  message: message,
-                  crontab: crontab,
-                  channel_id: req.body.channel_id,
-              };
-              job_crons[id] = cron.schedule(crontab, () => {
-                  client.channels.cache.get(req.body.channel_id).send(message);
-              }, {
-                  scheduled: true,
-                  timezone: process.env.TIMEZONE
-              });
-
-              const json = JSON.stringify(jobs);
-              fs.writeFile('jobs.json', json, 'utf8', err => {
-                  if (err) {
-                      console.error(err);
-                  }
-              });
-           }
-
-          return res.send({
-              type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
-              data: {
-                  content: content,
-              },
-          });
-      } else if (name === 'unschedule_message') {
-          const id = options[0].value;
-          const content = id in jobs ? `stopped job ${id}` : `no such job ${id}`;
-          if (id in jobs) {
-              job_crons[id].stop();
-              delete jobs[id]
-              delete job_crons[id];
-
-              const json = JSON.stringify(jobs);
-              fs.writeFile('jobs.json', json, 'utf8', err => {
-                  if (err) {
-                      console.error(err);
-                  }
-              });
-          }
-
-          return res.send({
-              type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
-              data: {
-                  content: content,
-              },
-          });
-      } else if (name === 'pet') {
-          return res.send({
-              type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
-              data: {
-                  content: '[purring noises]',
-              },
-          });
-      }
-
-    console.error(`unknown command: ${name}`);
-    return res.status(400).json({ error: 'unknown command' });
-  }
-
-  console.error('unknown interaction type', type);
-  return res.status(400).json({ error: 'unknown interaction type' });
-});
+    state.client.login(process.env.DISCORD_TOKEN);
+
+    const app = express();
+    const PORT = process.env.PORT || 3000;
+
+    app.post(
+        "/",
+        verifyKeyMiddleware(process.env.PUBLIC_KEY),
+        async (req, res) => {
+            const { type, data, channel_id } = req.body;
+
+            state.res = res;
+            switch (type) {
+                case InteractionType.PING:
+                    return res.send({ type: InteractionResponseType.PONG });
+                case InteractionType.APPLICATION_COMMAND:
+                    return handle_application_command(state, data, channel_id);
+                default:
+                    console.error("unknown interaction type", type);
+                    return res
+                        .status(400)
+                        .json({ error: "unknown interaction type" });
+            }
+        },
+    );
+
+    app.listen(PORT, () => {
+        console.log("Listening on port", PORT);
+    });
+}
 
-app.listen(PORT, () => {
-  console.log('Listening on port', PORT);
-});
+main();
-- 
cgit v1.2.3