From eb53e56dc7f3e5f7db59d312c4ad4e33f0aa9560 Mon Sep 17 00:00:00 2001 From: Dunemask Date: Mon, 22 Jan 2024 11:04:19 -0700 Subject: [PATCH] [FEATURE] Very basic server updates --- lib/controllers/lifecycle-controller.js | 32 ++++- lib/database/queries/server-queries.js | 46 ++++++- lib/routes/server-route.js | 4 + src/components/server-options/CpuOption.jsx | 2 +- .../server-options/ExtraPortsOption.jsx | 3 +- src/components/server-options/HostOption.jsx | 3 +- .../server-options/MemoryOption.jsx | 2 +- src/components/server-options/NameOption.jsx | 3 +- .../server-options/ServerTypeOption.jsx | 2 +- .../server-options/VersionOption.jsx | 2 +- src/components/servers/ServerCard.jsx | 1 + src/nav/MCLPages.jsx | 10 +- src/pages/CreateCoreOptions.jsx | 8 +- src/pages/Edit.jsx | 14 ++ src/pages/EditCoreOptions.jsx | 129 ++++++++++++++++++ src/util/queries.js | 8 ++ 16 files changed, 255 insertions(+), 14 deletions(-) create mode 100644 src/pages/Edit.jsx create mode 100644 src/pages/EditCoreOptions.jsx diff --git a/lib/controllers/lifecycle-controller.js b/lib/controllers/lifecycle-controller.js index 57b8385..b259d5d 100644 --- a/lib/controllers/lifecycle-controller.js +++ b/lib/controllers/lifecycle-controller.js @@ -4,8 +4,9 @@ import { createServerEntry, deleteServerEntry, getServerEntry, + modifyServerEntry, } from "../database/queries/server-queries.js"; -import { sendError } from "../util/ExpressClientError.js"; +import ExpressClientError, { sendError } from "../util/ExpressClientError.js"; import { toggleServer } from "../k8s/k8s-server-control.js"; const dnsRegex = new RegExp( @@ -18,6 +19,8 @@ function payloadFilter(req, res) { const { name, host, version, serverType, memory, extraPorts } = serverSpec; const { backupHost, backupBucket, backupId, backupKey, backupInterval } = serverSpec; + console.log("GOT VVV"); + console.log(serverSpec); if (!name) return res.status(400).send("Server name is required!"); if (!host) return res.status(400).send("Server host is required!"); if (!dnsRegex.test(host)) return res.status(400).send("Hostname invalid!"); @@ -117,3 +120,30 @@ export async function stopServer(req, res) { .then(() => res.sendStatus(200)) .catch(sendError(res)); } + +export async function getServer(req, res) { + // Ensure spec is safe + const serverSpec = req.body; + try { + checkServerId(serverSpec); + } catch (e) { + return sendError(res)(e); + } + const { id } = serverSpec; + getServerEntry(id).then((s) => res.json(s)); +} + +export async function modifyServer(req, res) { + if (payloadFilter(req, res) !== "filtered") return; + const serverSpec = req.body; + try { + checkServerId(serverSpec); + const serverEntry = await modifyServerEntry(serverSpec); + console.log("NEW ENTRY"); + console.log(serverEntry); + // await createServerResources(serverEntry); + res.sendStatus(200); + } catch (e) { + sendError(res)(e); + } +} diff --git a/lib/database/queries/server-queries.js b/lib/database/queries/server-queries.js index 93e84bd..cce9b55 100644 --- a/lib/database/queries/server-queries.js +++ b/lib/database/queries/server-queries.js @@ -1,5 +1,10 @@ import pg from "../postgres.js"; -import { deleteQuery, insertQuery, selectWhereQuery } from "../pg-query.js"; +import { + deleteQuery, + insertQuery, + selectWhereQuery, + updateWhereAllQuery, +} from "../pg-query.js"; import ExpressClientError from "../../util/ExpressClientError.js"; const table = "servers"; @@ -128,6 +133,45 @@ export async function getServerEntry(serverId) { } } +export async function modifyServerEntry(serverSpec) { + const { + id, + name, + host, + version, + serverType: server_type, + memory, + extraPorts: extra_ports, + backupEnabled: backup_enabled, + backupHost: backup_host, + backupBucket: backup_bucket_path, + backupId: backup_id, + backupKey: backup_key, + backupInterval: backup_interval, + } = serverSpec; + + const q = updateWhereAllQuery( + table, + { + name, + host, + version, + server_type, + memory, + extra_ports, + backup_enabled, + backup_host, + backup_bucket_path, + backup_id, + backup_key, + backup_interval, + }, + { id }, + ); + + return pg.query(q); +} + export async function getServerEntries() { const q = `SELECT * FROM ${table}`; return pg.query(q); diff --git a/lib/routes/server-route.js b/lib/routes/server-route.js index 7361abd..d6eb922 100644 --- a/lib/routes/server-route.js +++ b/lib/routes/server-route.js @@ -4,6 +4,8 @@ import { deleteServer, startServer, stopServer, + getServer, + modifyServer, } from "../controllers/lifecycle-controller.js"; import { serverInstances, @@ -18,4 +20,6 @@ router.post("/start", startServer); router.post("/stop", stopServer); router.get("/list", serverList); router.get("/instances", serverInstances); +router.post("/blueprint", getServer); +router.post("/modify", modifyServer); export default router; diff --git a/src/components/server-options/CpuOption.jsx b/src/components/server-options/CpuOption.jsx index 8eb8a83..ebc812c 100644 --- a/src/components/server-options/CpuOption.jsx +++ b/src/components/server-options/CpuOption.jsx @@ -12,7 +12,7 @@ export default function CpuOption(props) { p !== "25565" && p !== "25575" && p.length < 6; export default function ExtraPortsOption(props) { - const [extraPorts, setExtraPorts] = useState([]); + const { extraPorts: initExtraPorts } = props; + const [extraPorts, setExtraPorts] = useState(initExtraPorts ?? []); const { onChange } = props; function portChange(e, val, optionType, changedValue) { diff --git a/src/components/server-options/HostOption.jsx b/src/components/server-options/HostOption.jsx index 7efe6a9..d03d1db 100644 --- a/src/components/server-options/HostOption.jsx +++ b/src/components/server-options/HostOption.jsx @@ -1,10 +1,11 @@ import TextField from "@mui/material/TextField"; export default function HostOption(props) { - const { onChange } = props; + const { value, onChange } = props; return ( diff --git a/src/nav/MCLPages.jsx b/src/nav/MCLPages.jsx index 56ab52e..c2518c7 100644 --- a/src/nav/MCLPages.jsx +++ b/src/nav/MCLPages.jsx @@ -1,6 +1,7 @@ import Home from "@mcl/pages/Home.jsx"; import Create from "@mcl/pages/Create.jsx"; import Files from "@mcl/pages/Files.jsx"; +import Edit from "@mcl/pages/Edit.jsx"; // Go To https://mui.com/material-ui/material-icons/ for more! import HomeIcon from "@mui/icons-material/Home"; import AddIcon from "@mui/icons-material/Add"; @@ -21,10 +22,17 @@ export default [ visible: true, }, { - name: "Edit", + name: "Files", path: "/mcl/files", icon: , component: , visible: false, }, + { + name: "Edit", + path: "/mcl/edit", + icon: , + component: , + visible: false, + }, ]; diff --git a/src/pages/CreateCoreOptions.jsx b/src/pages/CreateCoreOptions.jsx index afe2f0d..4d68121 100644 --- a/src/pages/CreateCoreOptions.jsx +++ b/src/pages/CreateCoreOptions.jsx @@ -55,8 +55,8 @@ export default function CreateCoreOptions() { async function upsertSpec() { if (validateSpec() !== "validated") return; - createServer(spec) - // .then(() => nav("/")) + createServer() + .then(() => nav("/")) .catch(alert); } @@ -90,8 +90,8 @@ export default function CreateCoreOptions() { sx={{ width: "100%", maxWidth: "600px", margin: "auto" }} > - - + + + + + + + ); +} diff --git a/src/pages/EditCoreOptions.jsx b/src/pages/EditCoreOptions.jsx new file mode 100644 index 0000000..c5fbd64 --- /dev/null +++ b/src/pages/EditCoreOptions.jsx @@ -0,0 +1,129 @@ +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import FormControl from "@mui/material/FormControl"; +import FormControlLabel from "@mui/material/FormControlLabel"; +import Switch from "@mui/material/Switch"; +import Typography from "@mui/material/Typography"; +import { useGetServer, useModifyServer } from "@mcl/queries"; + +// Core Options +import NameOption from "@mcl/components/server-options/NameOption.jsx"; +import HostOption from "@mcl/components/server-options/HostOption.jsx"; +import VersionOption from "@mcl/components/server-options/VersionOption.jsx"; +import ServerTypeOption, { + serverTypeOptions, +} from "@mcl/components/server-options/ServerTypeOption.jsx"; +import CpuOption, { + cpuOptions, +} from "@mcl/components/server-options/CpuOption.jsx"; +import MemoryOption, { + memoryOptions, +} from "@mcl/components/server-options/MemoryOption.jsx"; +import ExtraPortsOption from "@mcl/components/server-options/ExtraPortsOption.jsx"; + +import BackupHostOption from "@mcl/components/server-options/BackupHostOption.jsx"; +import BackupBucketOption from "@mcl/components/server-options/BackupBucketOption.jsx"; +import BackupIdOption from "@mcl/components/server-options/BackupIdOption.jsx"; +import BackupKeyOption from "@mcl/components/server-options/BackupKeyOption.jsx"; +import BackupIntervalOption, { + backupIntervalDefault, +} from "@mcl/components/server-options/BackupIntervalOption.jsx"; + +export default function EditCoreOptions(props) { + const { serverId } = props; + const [backupEnabled, setBackupEnabled] = useState(false); + const [spec, setSpec] = useState(); + const modifyServer = useModifyServer(spec); + const { isLoading, data: serverBlueprint } = useGetServer(serverId); + + useEffect(() => setSpec(serverBlueprint), [serverBlueprint]); + + const updateSpec = (attr, val) => { + const s = { ...spec }; + s[attr] = val; + setSpec(s); + }; + + const coreUpdate = (attr) => (e) => updateSpec(attr, e.target.value); + + const upsertSpec = () => { + console.log(spec); + modifyServer(spec); + }; + + function validateSpec() { + console.log("TODO CREATE VALIDATION"); + if (!spec.host) return alertValidationError("Host cannot be blank"); + if (!spec.name) return alertValidationError("Name not included"); + if (!spec.version) return alertValidationError("Version cannot be blank"); + return "validated"; + } + + function alertValidationError(reason) { + alert(`Could not validate spec because: ${reason}`); + } + + if (!spec) return; // TODO: Add loading for spec + return ( + + + + + + + + + + + + } + label="Enable Backups?" + labelPlacement="start" + sx={{ mr: "auto" }} + /> + {backupEnabled && ( + + Backups + + + + + + + )} + + + + + ); +} diff --git a/src/util/queries.js b/src/util/queries.js index 2e02366..c80be01 100644 --- a/src/util/queries.js +++ b/src/util/queries.js @@ -39,6 +39,14 @@ export const useDeleteServer = (serverId) => postJsonApi("/server/delete", { id: serverId }, "server-instances", "DELETE"); export const useCreateServer = (spec) => postJsonApi("/server/create", spec, "server-list"); +export const useModifyServer = (spec) => + postJsonApi("/server/modify", spec, "server-list"); + +export const useGetServer = (serverId) => + useQuery({ + queryKey: [`server-blueprint-${serverId}`], + queryFn: fetchApiPost("/server/blueprint", { id: serverId }), + }); export const getServerFiles = async (serverId, path) => fetchApiCore("/files/list", { id: serverId, path }, "POST", true);