From 162708812d8f45511a2c9bab325539e8e3e3fa6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Jurmanovi=C4=87?= Date: Thu, 5 Oct 2023 19:06:01 +0200 Subject: [PATCH] fix error handling and more swagger info --- bun.lockb | Bin 89135 -> 88865 bytes package.json | 4 +- process-env.d.ts | 1 + src/app.ts | 182 +++++++++++++++++++++++++++++----------- src/constants/config.ts | 1 + src/core/basicAuth.ts | 14 +--- src/core/index.ts | 2 +- 7 files changed, 139 insertions(+), 65 deletions(-) diff --git a/bun.lockb b/bun.lockb index a98a5541139335cf431cc4ceefa631617a28faed..0a73e0143465463f8f976d613d68c955faadbc21 100644 GIT binary patch delta 12554 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 J2Md4sKLAlphco~H delta 12666 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 Yv!X?ewj*71(mr`agzs$ohzOJa3&je_mH+?% diff --git a/package.json b/package.json index f1aac22..5ff5a98 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "legica-dana", - "version": "2.0.0", + "version": "2.0.1", "main": "src/app.ts", "scripts": { "start": "bun src/app.ts" @@ -8,12 +8,12 @@ "author": "Fran Jurmanović ", "license": "MIT", "dependencies": { + "@elysiajs/cron": "^0.7.0", "@elysiajs/static": "^0.7.1", "@elysiajs/swagger": "^0.7.3", "axios": "^0.26.0", "body-parser": "^1.20.2", "cheerio": "^1.0.0-rc.10", - "cron": "^3.0.0", "discord.js": "^12.5.1", "dotenv": "^8.2.0", "elysia": "^0.7.15", diff --git a/process-env.d.ts b/process-env.d.ts index b614818..f2489d7 100644 --- a/process-env.d.ts +++ b/process-env.d.ts @@ -5,6 +5,7 @@ declare global { PORT: string; CRON_LEGICA: string; PASSWORD: string; + TIMEZONE: string; } } } diff --git a/src/app.ts b/src/app.ts index ef9948b..c0380d9 100644 --- a/src/app.ts +++ b/src/app.ts @@ -1,12 +1,12 @@ import { Client } from "discord.js"; import { config } from "@constants"; -import { CronJob } from "cron"; import { sendDiscordMessage, sendNextMessage } from "@common"; import { Elysia, t } from "elysia"; import { swagger } from "@elysiajs/swagger"; -import { basicAuth } from "@core"; +import { basicAuth, BasicAuthError } from "@core"; import pino from "pino"; import staticPlugin from "@elysiajs/static"; +import cron from "@elysiajs/cron"; const client: Client = new Client(); @@ -23,27 +23,39 @@ const logger = pino( ); const taskPlugin = new Elysia({ prefix: "/job" }) - .state("job", null as CronJob | null) - .onStart(({ store }) => { - client.on("ready", (): void => { - if (store.job) { - store.job.stop(); - } - store.job = new CronJob( - config.CRON_LEGICA, - () => sendNextMessage(client), - null, - true, - "utc" - ); - }); - }) - .onBeforeHandle(({ store: { job }, set }) => { - if (!job) { - set.status = 400; - return "Job is not running."; + .use( + cron({ + name: "job", + pattern: config.CRON_LEGICA, + run: () => sendNextMessage(client), + paused: true, + timezone: config.TIMEZONE, + }) + ) + .onStart( + ({ + store: { + cron: { job }, + }, + }) => { + client.on("ready", (): void => { + job.resume(); + }); } - }) + ) + .onBeforeHandle( + ({ + store: { + cron: { job }, + }, + set, + }) => { + if (job.isStopped()) { + set.status = 400; + return "Job is not running."; + } + } + ) .use( basicAuth({ users: [ @@ -55,26 +67,65 @@ const taskPlugin = new Elysia({ prefix: "/job" }) errorMessage: "Unauthorized", }) ) - .get("/", ({ store: { job } }) => ({ - running: job?.running ?? false, - next: job?.nextDate().toISO(), - })) - .post("/", ({ store: { job }, set }) => { - if (job?.running) { - set.status = 400; - return "Task already running"; + .get( + "/", + ({ + store: { + cron: { job }, + }, + }) => ({ + running: job.isRunning() ?? false, + stopped: job.isStopped() ?? false, + next: job.nextRun()?.toISOString(), + }), + { + detail: { + summary: "Get CRON job status", + }, } - job?.start(); - return "Task started"; - }) - .delete("/", ({ store: { job }, set }) => { - if (!job?.running) { - set.status = 400; - return "Task already stopped"; + ) + .post( + "/", + ({ + store: { + cron: { job }, + }, + set, + }) => { + if (job.isRunning()) { + set.status = 400; + return "Job already running"; + } + job.resume(); + return "Job started"; + }, + { + detail: { + summary: "Start CRON job if it is not running", + }, } - job?.stop(); - return "Task stopped"; - }) + ) + .delete( + "/", + ({ + store: { + cron: { job }, + }, + set, + }) => { + if (!job.isRunning()) { + set.status = 400; + return "Job already paused"; + } + job.pause(); + return "Job paused"; + }, + { + detail: { + summary: "Pause CRON job if it is not paused", + }, + } + ) .post( "/send", async ({ set, body }) => { @@ -95,18 +146,42 @@ const taskPlugin = new Elysia({ prefix: "/job" }) body: t.Object({ url: t.String(), }), + detail: { + summary: "Send legica-dana post to discord channels", + }, } ) - .get("/log", () => Bun.file("app.log")); - -client.login(config.TOKEN); - + .get("/log", () => Bun.file("app.log"), { + detail: { + summary: "Get the error log", + }, + }); const app = new Elysia() - .onError(({ error }) => { - logger.error(error); - return new Response(error.toString()); + .error({ BASIC_AUTH_ERROR: BasicAuthError }) + .onError(({ error, code }) => { + switch (code) { + case "BASIC_AUTH_ERROR": + return new Response(error.message, { + status: 401, + headers: { + "WWW-Authenticate": `Basic${ + config.realm ? ` realm="${config.realm}"` : "" + }`, + }, + }); + case "NOT_FOUND": + return new Response(error.message, { + status: 404, + }); + default: + logger.error(error); + } + }) + .get("/", () => config.APP_VERSION, { + detail: { + summary: "Get current API version", + }, }) - .get("/", () => config.APP_VERSION) .use( swagger({ documentation: { @@ -114,6 +189,14 @@ const app = new Elysia() title: "Legica Bot", version: config.APP_VERSION, }, + security: [ + { + type: ["basic"], + }, + ], + }, + swaggerOptions: { + withCredentials: true, }, }) ) @@ -121,6 +204,7 @@ const app = new Elysia() .use(taskPlugin) .listen(config.PORT); +client.login(config.TOKEN); console.log( - `🦊 Elysia is running at ${app.server?.hostname}:${app.server?.port}` + `🦊 Elysia is running at http://${app.server?.hostname}:${app.server?.port}` ); diff --git a/src/constants/config.ts b/src/constants/config.ts index 93130aa..e807ab3 100644 --- a/src/constants/config.ts +++ b/src/constants/config.ts @@ -16,6 +16,7 @@ const config: ProjectConfig = { CRON_LEGICA: process.env.CRON_LEGICA || "0 9 * * *", APP_VERSION: version, LEGICA_URL: "https://sib.net.hr/legica-dana", + TIMEZONE: process.env.TIMEZONE || "utc", }; export { config }; diff --git a/src/core/basicAuth.ts b/src/core/basicAuth.ts index 3e34a63..e7456fb 100644 --- a/src/core/basicAuth.ts +++ b/src/core/basicAuth.ts @@ -22,7 +22,6 @@ export interface BasicAuthConfig { export const basicAuth = (config: BasicAuthConfig) => new Elysia({ name: "basic-auth", seed: config }) - .error({ BASIC_AUTH_ERROR: BasicAuthError }) .derive((ctx) => { const authorization = ctx.headers?.authorization; if (!authorization) return { basicAuth: { isAuthed: false, username: "" } }; @@ -40,19 +39,8 @@ export const basicAuth = (config: BasicAuthConfig) => !isPathExcluded(ctx.path, config.exclude) && ctx.request && ctx.request.method !== "OPTIONS" - ) + ) { throw new BasicAuthError(config.errorMessage ?? "Unauthorized"); - }) - .onError((ctx) => { - if (ctx.code === "BASIC_AUTH_ERROR") { - return new Response(ctx.error.message, { - status: 401, - headers: { - "WWW-Authenticate": `Basic${ - config.realm ? ` realm="${config.realm}"` : "" - }`, - }, - }); } }); diff --git a/src/core/index.ts b/src/core/index.ts index 06d786c..bad3eba 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1 +1 @@ -export { basicAuth } from "./basicAuth"; +export { basicAuth, BasicAuthError } from "./basicAuth";