From 2e2bf70192f80500e493dc0f8f8a4c153609e6c8 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Thu, 26 Jan 2023 18:15:55 +0100 Subject: [PATCH 1/6] Shorten message --- src/bots/slackbot.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/bots/slackbot.ts b/src/bots/slackbot.ts index 9c78e9f..313418b 100644 --- a/src/bots/slackbot.ts +++ b/src/bots/slackbot.ts @@ -218,12 +218,7 @@ export namespace SlackBot { export function notifyOfNewLock(projectName: string) { DB.allNotifiableEvaluators((user) => { - SlackBot.sendMessage( - user, - `A new Peer++ evaluation for the project \`${projectName}\` is ready.` + - `Use the command \`/book\` to book it.` + - `Use the command \`/notify-off\` to stop receiving these notifications.` - ); + SlackBot.sendMessage(user, `A new Peer++ evaluation for \`${projectName}\` is ready to be booked`); }); } From 22b11610c4174ecac4860f500974456bc07cea13 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Thu, 26 Jan 2023 18:33:20 +0100 Subject: [PATCH 2/6] Use middleware --- src/bots/webhook.ts | 61 ++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/src/bots/webhook.ts b/src/bots/webhook.ts index f8e0d4a..60efce5 100644 --- a/src/bots/webhook.ts +++ b/src/bots/webhook.ts @@ -23,21 +23,30 @@ import * as Checks from "../checks/index"; * @param secret The Webhook secret. * @returns Status code and error message. */ -function filterHook(req: Request, secret: string) { - // TODO: Check for duplicate delivery ID, sometimes intra is stupid and sends it twice. - if (!req.is("application/json")) { - return { code: 400, msg: "Content-Type is not application/json" }; - } - if (!req.headers["x-delivery"]) { - return { code: 400, msg: "X-Delivery header missing" }; - } - if (!req.headers["x-secret"]) { - return { code: 400, msg: "X-Secret header missing" }; - } - if (req.headers["x-secret"] !== secret) { - return { code: 412, msg: "X-Secret header incorrect" }; - } - return null; +function filterHook(secret: string): (req: Request, res: Response, next: NextFunction) => void { + return (req: Request, res: Response, next: NextFunction) => { + // TODO: Check for duplicate delivery ID + let filter; + if (!req.is("application/json")) { + filter = { code: 400, msg: "Content-Type is not application/json" }; + } + if (!req.headers["x-delivery"]) { + filter = { code: 400, msg: "X-Delivery header missing" }; + } + if (!req.headers["x-secret"]) { + filter = { code: 400, msg: "X-Secret header missing" }; + } + if (req.headers["x-secret"] !== secret) { + filter = { code: 412, msg: "X-Secret header incorrect" }; + } + + if (filter) { + Logger.log(`Webhook filtered: ${filter}`); + res.status(filter.code).send(filter.msg); + } else { + next(); + } + }; } /** @@ -140,14 +149,8 @@ webhookApp.use((err: any, req: Request, res: Response, next: NextFunction) => { // TODO: Figure out how evaluation points should be handled. // Runs whenever a ScaleTeam / Evaluation is created. -webhookApp.post("/create", async (req: Request, res: Response) => { +webhookApp.post("/create", filterHook(Env.WEBHOOK_CREATE_SECRET), async (req: Request, res: Response) => { const hook: IntraWebhook.Root = req.body; - const filter = filterHook(req, Env.WEBHOOK_CREATE_SECRET); - - if (filter) { - res.status(filter.code).send(filter.msg); - return Logger.log(`Webhook: ${filter}`); - } Logger.log(`Evaluation created: ${hook.team.name} -> ${hook.project.name}`); if (await blockPotentialEvaluation(hook)) { @@ -192,13 +195,8 @@ webhookApp.post("/create", async (req: Request, res: Response) => { /*============================================================================*/ // Runs whenever a ScaleTeam / Evaluation is destroyed. -webhookApp.post("/delete", async (req: Request, res: Response) => { +webhookApp.post("/delete", filterHook(Env.WEBHOOK_DELETE_SECRET), async (req: Request, res: Response) => { const hook: IntraWebhook.Root = req.body; - const filter = filterHook(req, Env.WEBHOOK_DELETE_SECRET); - if (filter) { - res.status(filter.code).send(filter.msg); - return Logger.log(`Webhook: ${filter}`); - } Logger.log(`Evaluation destroyed: ${hook.team.name} -> ${hook.project.name}`); if (hook.user && hook.user.id != Config.botID) { @@ -231,13 +229,8 @@ webhookApp.post("/delete", async (req: Request, res: Response) => { /*============================================================================*/ // Runs whenever a ScaleTeam / Evaluation is changed in some way. -webhookApp.post("/update", async (req: Request, res: Response) => { +webhookApp.post("/update", filterHook(Env.WEBHOOK_UPDATE_SECRET), async (req: Request, res: Response) => { const hook: IntraWebhook.Root = req.body; - const filter = filterHook(req, Env.WEBHOOK_UPDATE_SECRET); - if (filter) { - res.status(filter.code).send(filter.msg); - return Logger.log(`Webhook: ${filter}`); - } Logger.log(`Evaluation update: ${hook.team.name} -> ${hook.project.name}`); From b58ab8e422f8d3a6ddac8bff360f89e4dc0c7c34 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Thu, 26 Jan 2023 18:49:34 +0100 Subject: [PATCH 3/6] refactor --- src/db.ts | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/db.ts b/src/db.ts index 08ddd5e..bc30028 100644 --- a/src/db.ts +++ b/src/db.ts @@ -12,48 +12,50 @@ import { User } from "./utils/user"; async function dbRun(query: string): Promise { return await new Promise((resolve, reject) => { - db.run(query, (err) => (err ? reject(err) : resolve())); + db.run(query, (err) => { + if (err) { + err.message = `Query failed: "${query}"\n${err.message}`; + return reject(err); + } + resolve(); + }); + }); +} + +async function dbGet(query: string): Promise { + return new Promise((resolve, reject) => { + db.get(query, (err, t) => { + if (err) { + err.message = `Query failed: "${query}"\n${err.message}`; + return reject(err); + } + resolve(t); + }); }); } /** SQLlite3 database wrapper functions */ namespace DB { /** Deletes all expiredTeam rows which are older than the lock days. */ - export function emptyOldLocks() { - return new Promise((resolve, reject) => { - db.run(`DELETE FROM expiredTeam WHERE datetime(created_at) < datetime('now', '-${Config.lockExpirationDays} days')`, (err) => { - if (err != null) return reject(`Failed to clear database: ${err}`); - return resolve(); - }); - }); + export async function emptyOldLocks() { + await dbRun(`DELETE FROM expiredTeam WHERE datetime(created_at) < datetime('now', '-${Config.lockExpirationDays} days')`); } /** * Insert the given team into the database and mark them as expired. * @param teamID The TeamID. */ - export function insert(teamID: number) { - return new Promise((resolve, reject) => { - db.run(`INSERT INTO expiredTeam(teamID) VALUES(${teamID})`, (err) => { - if (err != null) return reject(`Failed to insert value ${teamID}: ${err}`); - return resolve(); - }); - }); + export async function insert(teamID: number) { + await dbRun(`INSERT INTO expiredTeam(teamID) VALUES(${teamID})`); } /** * Checks wether the given teamID exists in the db. * @param teamID The TeamID. */ - export function exists(teamID: number) { - return new Promise((resolve, reject) => { - db.get(`SELECT COUNT(*) AS amount FROM expiredTeam WHERE teamID = ${teamID}`, (err, row) => { - if (err != null) { - return reject(`Failed to check if ${teamID} exists: ${err}`); - } - return resolve(row["amount"] > 0); - }); - }); + export async function exists(teamID: number) { + const team = await dbGet<{ amount: number }>(`SELECT COUNT(*) AS amount FROM expiredTeam WHERE teamID = ${teamID}`); + return team.amount > 0; } export async function saveEvaluator(user: User, notify: boolean): Promise { From 2ec02db6b69d7e68f4b1564fc2c8296718c1b476 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Thu, 26 Jan 2023 19:59:58 +0100 Subject: [PATCH 4/6] Remove unnecessary index.ts --- src/bots/webhook.ts | 4 ++-- src/checks/evaluators.ts | 6 +++++- src/checks/index.ts | 9 --------- src/checks/random.ts | 18 ------------------ 4 files changed, 7 insertions(+), 30 deletions(-) delete mode 100644 src/checks/index.ts delete mode 100644 src/checks/random.ts diff --git a/src/bots/webhook.ts b/src/bots/webhook.ts index 60efce5..bb0600e 100644 --- a/src/bots/webhook.ts +++ b/src/bots/webhook.ts @@ -13,7 +13,7 @@ import { getFullUser } from "../utils/user"; import { IntraWebhook } from "../utils/types"; import Logger, { LogType } from "../utils/logger"; import { Request, Response, NextFunction } from "express"; -import * as Checks from "../checks/index"; +import * as Checks from "../checks/evaluators"; /*============================================================================*/ @@ -108,7 +108,7 @@ export namespace Webhook { // NOTE (W2): Completely fucked up and weird endpoint btw. const teamUsers = await Intra.getTeamUsers(hook.team.id); - return (await Checks.Evaluators(hook, evaluations, teamUsers)) || (await Checks.Random()); + return (await Checks.evaluators(hook, evaluations, teamUsers)) || Checks.random(); } /** diff --git a/src/checks/evaluators.ts b/src/checks/evaluators.ts index 2cc879a..b6ed85e 100644 --- a/src/checks/evaluators.ts +++ b/src/checks/evaluators.ts @@ -21,7 +21,7 @@ import { getFullUser, User } from "../utils/user"; * @param evaluations The evaluations of the project. * @return True if an evaluation is required, else false. */ -export async function Evaluators(hook: IntraWebhook.Root, evaluations: Intra.ScaleTeam[], teamUsers: IntraResponse.TeamUser[]) { +export async function evaluators(hook: IntraWebhook.Root, evaluations: Intra.ScaleTeam[], teamUsers: IntraResponse.TeamUser[]) { const leaderData = teamUsers.find((value) => value.leader == true)!; let levels: number[] = []; @@ -49,3 +49,7 @@ export async function Evaluators(hook: IntraWebhook.Root, evaluations: Intra.Sca } return true; } + +export function random() { + return Math.random() < Config.randomEvalChance / 100; +} diff --git a/src/checks/index.ts b/src/checks/index.ts deleted file mode 100644 index 1c98791..0000000 --- a/src/checks/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -// ----------------------------------------------------------------------------- -// Codam Coding College, Amsterdam @ 2022. -// See README in the root project for more information. -// ----------------------------------------------------------------------------- - -// NOTE (W2): This seems janky as hell but apparently this is how TS works ? - -export * from "./evaluators"; -export * from "./random"; diff --git a/src/checks/random.ts b/src/checks/random.ts deleted file mode 100644 index f875b05..0000000 --- a/src/checks/random.ts +++ /dev/null @@ -1,18 +0,0 @@ -// ----------------------------------------------------------------------------- -// Codam Coding College, Amsterdam @ 2022. -// See README in the root project for more information. -// ----------------------------------------------------------------------------- - -import { Config } from "../config"; - -/*============================================================================*/ - -/** - * Simply randomly decide if an evaluation is required. - * The weight / probability can be altered via the config. - * - * @return True if check passed, false otherwise. - */ -export async function Random() { - return Math.random() < Config.randomEvalChance / 100; -} From 0ff0a39cec9c45bbebcc290bcede4baa453ad370 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Fri, 10 Feb 2023 11:34:18 +0100 Subject: [PATCH 5/6] Use filter --- src/bots/webhook.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bots/webhook.ts b/src/bots/webhook.ts index 9916db6..c45328b 100644 --- a/src/bots/webhook.ts +++ b/src/bots/webhook.ts @@ -44,14 +44,11 @@ async function filterAlreadyDeliveredWebhook(req: Request) { } /** - * Filters for requests and sends back corresponding error. - * @param req The incoming request. + * Filters for requests and, if required sends corresponding error. * @param secret The Webhook secret. - * @returns Status code and error message. */ -function filterHook(secret: string): (req: Request, res: Response, next: NextFunction) => void { - return (req: Request, res: Response, next: NextFunction) => { - // TODO: Check for duplicate delivery ID +function filterHook(secret: string): (req: Request, res: Response, next: NextFunction) => Promise { + return async (req: Request, res: Response, next: NextFunction) => { let filter; if (!req.is("application/json")) { filter = { code: 400, msg: "Content-Type is not application/json" }; @@ -65,6 +62,9 @@ function filterHook(secret: string): (req: Request, res: Response, next: NextFun if (req.headers["x-secret"] !== secret) { filter = { code: 412, msg: "X-Secret header incorrect" }; } + if (await filterAlreadyDeliveredWebhook(req)) { + filter = { code: 200, msg: "Webhook already delivered" }; + } if (filter) { Logger.log(`Webhook filtered: ${filter}`); From 568ae173113c9868a304e6115203f4830374c624 Mon Sep 17 00:00:00 2001 From: Joppe Koers Date: Fri, 10 Feb 2023 11:46:42 +0100 Subject: [PATCH 6/6] fix --- src/bots/webhook.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/bots/webhook.ts b/src/bots/webhook.ts index c45328b..bddd883 100644 --- a/src/bots/webhook.ts +++ b/src/bots/webhook.ts @@ -49,25 +49,22 @@ async function filterAlreadyDeliveredWebhook(req: Request) { */ function filterHook(secret: string): (req: Request, res: Response, next: NextFunction) => Promise { return async (req: Request, res: Response, next: NextFunction) => { - let filter; + let filter: { code: number; msg: string } | undefined = undefined; + if (!req.is("application/json")) { filter = { code: 400, msg: "Content-Type is not application/json" }; - } - if (!req.headers["x-delivery"]) { + } else if (!req.headers["x-delivery"]) { filter = { code: 400, msg: "X-Delivery header missing" }; - } - if (!req.headers["x-secret"]) { + } else if (!req.headers["x-secret"]) { filter = { code: 400, msg: "X-Secret header missing" }; - } - if (req.headers["x-secret"] !== secret) { + } else if (req.headers["x-secret"] !== secret) { filter = { code: 412, msg: "X-Secret header incorrect" }; - } - if (await filterAlreadyDeliveredWebhook(req)) { + } else if (await filterAlreadyDeliveredWebhook(req)) { filter = { code: 200, msg: "Webhook already delivered" }; } if (filter) { - Logger.log(`Webhook filtered: ${filter}`); + Logger.log(`Webhook filtered: ${JSON.stringify(filter)}`); res.status(filter.code).send(filter.msg); } else { next();