From 0fff6aae0ec41525b3eaa9efdf1e2ced95b4e40b Mon Sep 17 00:00:00 2001 From: benrobson Date: Wed, 9 Oct 2024 21:46:55 +1100 Subject: [PATCH 1/8] Start the bridge draft. --- api/routes/bridge.js | 181 +++++++++++++++++++++++++++++++++++++++++++ dbinit.sql | 9 +++ 2 files changed, 190 insertions(+) create mode 100644 api/routes/bridge.js diff --git a/api/routes/bridge.js b/api/routes/bridge.js new file mode 100644 index 00000000..96b1ada7 --- /dev/null +++ b/api/routes/bridge.js @@ -0,0 +1,181 @@ +import { isFeatureEnabled, required, optional, generateLog } from "../common"; + +export default function bridgeApiRoute(app, config, db, features, lang) { + const baseEndpoint = "/api/bridge"; + + app.get(baseEndpoint + "/get", async function (req, res) { + isFeatureEnabled(features.bridge, res, lang); + const bridgeId = optional(req.query, "id"); + const targetedServer = optional(req.query, "targetedServer"); + + try { + function getBridge(dbQuery) { + db.query(dbQuery, function (error, results, fields) { + console.log(results); + + if (error) { + res.send({ + success: false, + message: `${error}`, + }); + } + + if (!results.length) { + return res.send({ + success: false, + message: `No Bridge requests can be found`, + }); + } + + return res.send({ + success: true, + data: results, + }); + }); + } + + // Get Bridge by ID + if (bridgeId) { + let dbQuery = `SELECT * FROM bridge WHERE bridgeId=${bridgeId};`; + getBridge(dbQuery); + } + + // Get Bridge by Targeted Server + if (bridgeId) { + let dbQuery = `SELECT * FROM bridge WHERE targetedServer=${targetedServer};`; + getBridge(dbQuery); + } + + // Return all Bridge requests by default + let dbQuery = `SELECT * FROM bridge;`; + getBridge(dbQuery); + } catch (error) { + res.send({ + success: false, + message: `${error}`, + }); + } + + return res; + }); + + app.post(baseEndpoint + "/command/add", async function (req, res) { + isFeatureEnabled(features.bridge, res, lang); + + const command = required(req.body, "command", res); + const targetedServer = required(req.body, "targetedServer", res); + + try { + db.query( + `INSERT INTO bridge + (command, targetedServer) + VALUES (?, ?)`, + [ + command, + targetedServer + ], + function (error, results, fields) { + if (error) { + return res.send({ + success: false, + message: `${error}`, + }); + } + + return res.send({ + success: true, + message: applicationCreatedLang.replace( + "%DISPLAYNAME%", + displayName + ), + }); + } + ); + } catch (error) { + res.send({ + success: false, + message: `${error}`, + }); + } + + return res; + }); + + app.post(baseEndpoint + "/command/process", async function (req, res) { + isFeatureEnabled(features.bridge, res, lang); + + const actioningUser = required(req.body, "actioningUser", res); + const applicationId = required(req.body, "applicationId", res); + const displayName = required(req.body, "displayName", res); + const description = required(req.body, "description", res); + const displayIcon = required(req.body, "displayIcon", res); + const requirementsMarkdown = required( + req.body, + "requirementsMarkdown", + res + ); + const redirectUrl = required(req.body, "redirectUrl", res); + const position = required(req.body, "position", res); + const applicationStatus = required(req.body, "applicationStatus", res); + + let applicationEditedLang = lang.applications.applicationEdited; + + try { + db.query( + ` + UPDATE + applications + SET + displayName=?, + displayIcon=?, + description=?, + requirementsMarkdown=?, + redirectUrl=?, + position=?, + applicationStatus=? + WHERE applicationId=?;`, + [ + displayName, + displayIcon, + description, + requirementsMarkdown, + redirectUrl, + position, + applicationStatus, + applicationId, + ], + function (error, results, fields) { + if (error) { + return res.send({ + success: false, + message: `${error}`, + }); + } + + generateLog( + actioningUser, + "SUCCESS", + "APPLICATION", + `Edited ${displayName}`, + res + ); + + return res.send({ + success: true, + message: applicationEditedLang.replace( + "%DISPLAYNAME%", + displayName + ), + }); + } + ); + } catch (error) { + res.send({ + success: false, + message: `${error}`, + }); + } + + return res; + }); +} diff --git a/dbinit.sql b/dbinit.sql index 6ec2f796..0fc2ee26 100644 --- a/dbinit.sql +++ b/dbinit.sql @@ -224,6 +224,15 @@ CREATE TABLE vault ( PRIMARY KEY (vaultId) ); +CREATE TABLE bridge ( + bridgeId INT NOT NULL AUTO_INCREMENT, + command TEXT, + targetedServer VARCHAR(30), + processed BOOLEAN DEFAULT 0, + bridgeDateTime DATETIME NOT NULL DEFAULT NOW(), + PRIMARY KEY (bridgeId) +); + CREATE TABLE logs ( logId INT NOT NULL AUTO_INCREMENT, creatorId INT NOT NULL, From ba0479403f63cbc081d9edcde5687ff9e78c4cc9 Mon Sep 17 00:00:00 2001 From: benrobson Date: Thu, 10 Oct 2024 22:28:39 +1100 Subject: [PATCH 2/8] API routes and dashboard UI --- api/routes/bridge.js | 68 ++++--------------- api/routes/index.js | 2 + features.json | 1 + routes/dashboard/dashboard.js | 32 ++++++++- views/dashboard/bridge.ejs | 59 ++++++++++++++++ views/modules/dashboard/dashboard-sidebar.ejs | 15 ++-- 6 files changed, 109 insertions(+), 68 deletions(-) create mode 100644 views/dashboard/bridge.ejs diff --git a/api/routes/bridge.js b/api/routes/bridge.js index 96b1ada7..0f3f10b2 100644 --- a/api/routes/bridge.js +++ b/api/routes/bridge.js @@ -67,13 +67,8 @@ export default function bridgeApiRoute(app, config, db, features, lang) { try { db.query( - `INSERT INTO bridge - (command, targetedServer) - VALUES (?, ?)`, - [ - command, - targetedServer - ], + `INSERT INTO bridge (command, targetedServer) VALUES (?, ?)`, + [command, targetedServer], function (error, results, fields) { if (error) { return res.send({ @@ -104,46 +99,18 @@ export default function bridgeApiRoute(app, config, db, features, lang) { app.post(baseEndpoint + "/command/process", async function (req, res) { isFeatureEnabled(features.bridge, res, lang); - const actioningUser = required(req.body, "actioningUser", res); - const applicationId = required(req.body, "applicationId", res); - const displayName = required(req.body, "displayName", res); - const description = required(req.body, "description", res); - const displayIcon = required(req.body, "displayIcon", res); - const requirementsMarkdown = required( - req.body, - "requirementsMarkdown", - res - ); - const redirectUrl = required(req.body, "redirectUrl", res); - const position = required(req.body, "position", res); - const applicationStatus = required(req.body, "applicationStatus", res); - - let applicationEditedLang = lang.applications.applicationEdited; + const bridgeId = required(req.body, "bridgeId", res); try { + const fetchURL = `${process.env.siteAddress}/api/bridge/get?id=${bridgeId}`; + const response = await fetch(fetchURL, { + headers: { "x-access-token": process.env.apiKey }, + }); + const bridgeApiData = await response.json(); + db.query( - ` - UPDATE - applications - SET - displayName=?, - displayIcon=?, - description=?, - requirementsMarkdown=?, - redirectUrl=?, - position=?, - applicationStatus=? - WHERE applicationId=?;`, - [ - displayName, - displayIcon, - description, - requirementsMarkdown, - redirectUrl, - position, - applicationStatus, - applicationId, - ], + `UPDATE bridge SET processed=? WHERE bridgeId=?;`, + [1, bridgeId], function (error, results, fields) { if (error) { return res.send({ @@ -152,20 +119,9 @@ export default function bridgeApiRoute(app, config, db, features, lang) { }); } - generateLog( - actioningUser, - "SUCCESS", - "APPLICATION", - `Edited ${displayName}`, - res - ); - return res.send({ success: true, - message: applicationEditedLang.replace( - "%DISPLAYNAME%", - displayName - ), + message: `Bridge ID ${bridgeId} has been executed with command: ${bridgeApiData.data[0]}`, }); } ); diff --git a/api/routes/index.js b/api/routes/index.js index 1b3db1b8..e5fbf09c 100644 --- a/api/routes/index.js +++ b/api/routes/index.js @@ -9,6 +9,7 @@ import filterApiRoute from "./filter"; import rankApiRoute from "./ranks"; import reportApiRoute from "./report"; import vaultApiRoute from "./vault"; +import bridgeApiRoute from "./bridge"; export default (app, client, moment, config, db, features, lang) => { announcementApiRoute(app, config, db, features, lang); @@ -22,6 +23,7 @@ export default (app, client, moment, config, db, features, lang) => { rankApiRoute(app, config, db, features, lang); filterApiRoute(app, config, db, features, lang); vaultApiRoute(app, config, db, features, lang); + bridgeApiRoute(app, config, db, features, lang); app.get("/api/heartbeat", async function (req, res) { return res.send({ diff --git a/features.json b/features.json index 20760f89..3c3b0533 100644 --- a/features.json +++ b/features.json @@ -12,6 +12,7 @@ "ranks": true, "report": true, "vault": true, + "bridge": true, "filter": { "link": true, "phrase": true diff --git a/routes/dashboard/dashboard.js b/routes/dashboard/dashboard.js index 4b8a2fc5..0df3acaa 100644 --- a/routes/dashboard/dashboard.js +++ b/routes/dashboard/dashboard.js @@ -14,9 +14,9 @@ export default function dashboardSiteRoute(app, config, features, lang) { res, features ); - + if (!permissionBoolean) return; - + return res.view("dashboard/dashboard-index", { pageTitle: `Dashboard`, config: config, @@ -52,4 +52,32 @@ export default function dashboardSiteRoute(app, config, features, lang) { return res; }); + + // + // Bridge + // + app.get("/dashboard/bridge", async function (req, res) { + if (!hasPermission("zander.web.bridge", req, res, features)) return; + + const fetchURL = `${process.env.siteAddress}/api/bridge/get`; + const response = await fetch(fetchURL, { + headers: { "x-access-token": process.env.apiKey }, + }); + const apiData = await response.json(); + + console.log(apiData); + + res.view("dashboard/bridge", { + pageTitle: `Dashboard - Bridge`, + config: config, + apiData: apiData, + features: features, + req: req, + globalImage: getGlobalImage(), + moment: moment, + announcementWeb: await getWebAnnouncement(), + }); + + return res; + }); } diff --git a/views/dashboard/bridge.ejs b/views/dashboard/bridge.ejs new file mode 100644 index 00000000..f075bc0a --- /dev/null +++ b/views/dashboard/bridge.ejs @@ -0,0 +1,59 @@ +<%- include("../modules/header.ejs", { + pageTitle: pageTitle, + pageDescription: "Bridge for sending commands and functions." +}) %> + +<%- include("../modules/navigationBar.ejs") %> + +<%- include("../partials/miniHeader.ejs", { + headerTitle: "Bridge", + backgroundImage: globalImage +}) %> + +
+
+ <%- include("../modules/dashboard/dashboard-sidebar.ejs") %> +
+
+ <% if (req.cookies.alertType) { %> + <%- include("../partials/alert.ejs", { + alertType: req.cookies.alertType, + content: req.cookies.alertContent + }) %> + <% } %> + + + + + + + + + + + <% if (apiData.success == false) { %> + <%- include("../partials/alert.ejs", { + alertType: "danger", + content: apiData.message + }) %> + <% } else { %> + <% apiData.data.forEach(function (log) { %> + + + + + + + + <% }) %> + <% } %> + +
Bridge IDCommandCreated
<%= log.actionedUsername %> + <%- include("../partials/logPriorityBadge.ejs", { + type: log.logType + }) %> + <%= log.logFeature %><%= log.description %><%= moment(log.actionedDateTime).startOf('hour').fromNow() %>
+
+
+ +<%- include("../modules/footer.ejs") %> \ No newline at end of file diff --git a/views/modules/dashboard/dashboard-sidebar.ejs b/views/modules/dashboard/dashboard-sidebar.ejs index 6fec9355..7606fada 100644 --- a/views/modules/dashboard/dashboard-sidebar.ejs +++ b/views/modules/dashboard/dashboard-sidebar.ejs @@ -20,18 +20,13 @@ Logs