From cda6cff34f1dd07b195031e5b9f369d61573d2d5 Mon Sep 17 00:00:00 2001 From: Benjamin Toby Date: Thu, 17 Sep 2026 08:43:00 +0100 Subject: [PATCH] Complete client form --- db/schema.ts | 14 ++++ .../backend/setup/setup-wireguard-client.ts | 2 +- .../grab-next-available-client-ip.ts | 41 ++++++++++ .../(functions)/submit-add-client-form.ts | 71 ++++++++++++++++ .../client-form/add-client-form-action.tsx | 20 +++++ .../add-client-form-allowed-ips.tsx | 23 ++++++ .../client-form/add-client-form-notes.tsx | 24 ++++++ .../client-form/add-client-form-title.tsx | 10 ++- .../add-client-form-wg-ip-address.tsx | 81 +++++++++++++++++++ .../client-form/add-client-form.tsx | 25 +++++- .../clients/(functions)/run-client-setup.ts | 57 +++++++++++++ .../api/admin/crud/(tables)/clients/del.ts | 63 +++++++++++++++ .../api/admin/crud/(tables)/clients/get.ts | 38 +++++++++ .../api/admin/crud/(tables)/clients/index.ts | 29 +++++++ .../api/admin/crud/(tables)/clients/post.ts | 52 ++++++++++++ .../api/admin/crud/(tables)/clients/put.ts | 56 +++++++++++++ src/pages/api/admin/crud/[[...paths]].ts | 3 + .../admin/grab-next-available-client-ip.ts | 55 +++++++++++++ src/types/index.ts | 1 + 19 files changed, 661 insertions(+), 4 deletions(-) create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/grab-next-available-client-ip.ts create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/submit-add-client-form.ts create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-action.tsx create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-allowed-ips.tsx create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-notes.tsx create mode 100644 src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-wg-ip-address.tsx create mode 100644 src/pages/api/admin/crud/(tables)/clients/(functions)/run-client-setup.ts create mode 100644 src/pages/api/admin/crud/(tables)/clients/del.ts create mode 100644 src/pages/api/admin/crud/(tables)/clients/get.ts create mode 100644 src/pages/api/admin/crud/(tables)/clients/index.ts create mode 100644 src/pages/api/admin/crud/(tables)/clients/post.ts create mode 100644 src/pages/api/admin/crud/(tables)/clients/put.ts create mode 100644 src/pages/api/admin/grab-next-available-client-ip.ts diff --git a/db/schema.ts b/db/schema.ts index decb0d6..13d199d 100644 --- a/db/schema.ts +++ b/db/schema.ts @@ -187,6 +187,20 @@ const schema: BUN_SQLITE_DatabaseSchemaType = { dataType: "TEXT", }, ], + uniqueConstraints: [ + { + constraintName: "Unique client IPs per host", + alias: "unique_client_ip_per_host", + constraintTableFields: [ + { + value: "host_id", + }, + { + value: "wg_ip_address", + }, + ], + }, + ], }, { tableName: "hosts", diff --git a/src/functions/backend/setup/setup-wireguard-client.ts b/src/functions/backend/setup/setup-wireguard-client.ts index fafead8..82a5400 100644 --- a/src/functions/backend/setup/setup-wireguard-client.ts +++ b/src/functions/backend/setup/setup-wireguard-client.ts @@ -65,7 +65,7 @@ export default async function setupWireguardClient({ ); const HOST_CLIENTS_DIR = path.join( - WGUI_LIB_HOSTS_CONFIGS_DIR, + HOST_CONFIG_DIR, WGUI_LIB_HOST_CLIENTS_DIR_NAME, ); diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/grab-next-available-client-ip.ts b/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/grab-next-available-client-ip.ts new file mode 100644 index 0000000..c45473a --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/grab-next-available-client-ip.ts @@ -0,0 +1,41 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import fetchApi from "@/src/components/twui/utils/fetch/fetchApi"; +import type useFormInit from "@/src/hooks/use-form-init"; +import type { ApiReqParams } from "@/src/types"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; + +type Params = { + host_id?: string | number; + setForm: ReturnType>["setForm"]; +}; + +export default async function grabNextAvailableClientIp({ + host_id, + setForm, +}: Params) { + const res = await fetchApi( + `/api/admin/grab-next-available-client-ip`, + { + method: "POST", + body: { host_id }, + }, + ); + + if (!res?.success || !res.msg) { + return { + success: false, + msg: res?.msg || `Couldn't grab the next available client IP`, + }; + } + + setForm((prev) => ({ + ...prev, + wg_ip_address: res.msg, + allowed_ips: `${res.msg}/32`, + })); + + return { + success: true, + msg: res.msg, + }; +} diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/submit-add-client-form.ts b/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/submit-add-client-form.ts new file mode 100644 index 0000000..68017e5 --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(functions)/submit-add-client-form.ts @@ -0,0 +1,71 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler"; +import type useFormInit from "@/src/hooks/use-form-init"; +import _ from "lodash"; + +type Params = { + host_id?: string | number; +}; + +export default async function submitAddClientForm( + { + setLoading, + setStatus, + form, + existing_full, + app_context, + }: ReturnType>, + { host_id }: Params, +) { + try { + if (!window.confirm(`Create new client?`)) { + return; + } + + const final_host_id = Number(app_context.query?.host_id || 0); + + const new_client_data: BUN_SQLITE_WGUI_CLIENTS = _.omitBy( + { + name: form.name || "", + wg_ip_address: form.wg_ip_address || "", + allowed_ips: form.allowed_ips || "", + notes: form.notes || "", + host_id: final_host_id, + user_id: app_context?.user?.id, + }, + (value) => value === undefined, + ); + + setLoading(true); + + const res = existing_full?.id + ? await adminCrudHandler({ + action: "update", + table: "clients", + update_data: new_client_data, + id: existing_full.id, + }) + : await adminCrudHandler({ + action: "insert", + table: "clients", + insert_data: [new_client_data], + }); + + if (res.success) { + if (existing_full?.id) { + window.location.reload(); + } else { + window.location.pathname = `/admin/hosts/${final_host_id}/clients`; + } + } else { + throw new Error(res.msg || "Client Creation Failed"); + } + } catch (error: any) { + setStatus({ + error: true, + msg: error.message || "Add Client Form Error", + }); + + setLoading(false); + } +} diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-action.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-action.tsx new file mode 100644 index 0000000..c529b78 --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-action.tsx @@ -0,0 +1,20 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import Button from "@/src/components/twui/layout/Button"; +import useFormInit from "@/src/hooks/use-form-init"; + +export default function AddClientFormAction({ + status, + existing_full, +}: ReturnType>) { + const title = existing_full?.id ? "Update Client" : "Create New Client"; + + if (status?.error) { + return null; + } + + return ( + + ); +} \ No newline at end of file diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-allowed-ips.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-allowed-ips.tsx new file mode 100644 index 0000000..a13637f --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-allowed-ips.tsx @@ -0,0 +1,23 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import Input from "@/src/components/twui/form/Input"; +import useFormInit from "@/src/hooks/use-form-init"; + +export default function AddClientFormAllowedIps({ + form, + setForm, +}: ReturnType>) { + return ( + { + setForm((prev) => ({ + ...prev, + allowed_ips: e.target.value, + })); + }} + value={form.allowed_ips} + showLabel + /> + ); +} diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-notes.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-notes.tsx new file mode 100644 index 0000000..ca61a91 --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-notes.tsx @@ -0,0 +1,24 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import Input from "@/src/components/twui/form/Input"; +import useFormInit from "@/src/hooks/use-form-init"; + +export default function AddClientFormNotes({ + form, + setForm, +}: ReturnType>) { + return ( + { + setForm((prev) => ({ + ...prev, + notes: e.target.value, + })); + }} + defaultValue={form.notes} + showLabel + /> + ); +} \ No newline at end of file diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-title.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-title.tsx index 5550460..110b41d 100644 --- a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-title.tsx +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-title.tsx @@ -10,7 +10,15 @@ export default function AddClientFormTitle({ { + setForm((prev) => ({ + ...prev, + name: e.target.value, + })); + }} + defaultValue={form.name} showLabel + required /> ); -} +} \ No newline at end of file diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-wg-ip-address.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-wg-ip-address.tsx new file mode 100644 index 0000000..573a69f --- /dev/null +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form-wg-ip-address.tsx @@ -0,0 +1,81 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import Button from "@/src/components/twui/layout/Button"; +import Input from "@/src/components/twui/form/Input"; +import Span from "@/src/components/twui/layout/Span"; +import Stack from "@/src/components/twui/layout/Stack"; +import useFormInit from "@/src/hooks/use-form-init"; +import { Wand2 } from "lucide-react"; +import { useState } from "react"; +import grabNextAvailableClientIp from "../../(functions)/grab-next-available-client-ip"; +import Row from "@/src/components/twui/layout/Row"; + +type Props = ReturnType> & { + host_id?: string | number; +}; + +export default function AddClientFormWgIpAddress({ + form, + setForm, + host_id, +}: Props) { + const [grabbing, setGrabbing] = useState(false); + const [grab_error, setGrabError] = useState(); + + function handleGrabNextIp() { + setGrabbing(true); + setGrabError(undefined); + + grabNextAvailableClientIp({ host_id, setForm }) + .then((res) => { + if (!res.success) { + setGrabError(res.msg); + } + }) + .finally(() => { + setGrabbing(false); + }); + } + + return ( + + + { + setForm((prev) => ({ + ...prev, + wg_ip_address: e.target.value, + allowed_ips: `${e.target.value}/32`, + })); + }} + value={form.wg_ip_address} + showLabel + /> + + + + + {grab_error ? ( + + {grab_error} + + ) : null} + + ); +} diff --git a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form.tsx b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form.tsx index e15ed5a..8a01884 100644 --- a/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form.tsx +++ b/src/pages/admin/hosts/[host_id]/clients/add-client/(partials)/client-form/add-client-form.tsx @@ -1,8 +1,15 @@ import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; import Form from "@/src/components/twui/form/Form"; +import LoadingOverlay from "@/src/components/twui/elements/LoadingOverlay"; import Stack from "@/src/components/twui/layout/Stack"; +import Tag from "@/src/components/twui/elements/Tag"; import useFormInit from "@/src/hooks/use-form-init"; +import submitAddClientForm from "../../(functions)/submit-add-client-form"; +import AddClientFormAction from "./add-client-form-action"; +import AddClientFormAllowedIps from "./add-client-form-allowed-ips"; +import AddClientFormNotes from "./add-client-form-notes"; import AddClientFormTitle from "./add-client-form-title"; +import AddClientFormWgIpAddress from "./add-client-form-wg-ip-address"; type Props = { existing_client?: BUN_SQLITE_WGUI_CLIENTS; @@ -21,11 +28,25 @@ export default function AddClientForm({ title: "Add Client", }); + const { loading, status } = init; + return ( -
+ { + submitAddClientForm(init, { host_id }); + }} + > + {status?.error && {status.msg}} + {loading && } + + + + + ); -} +} \ No newline at end of file diff --git a/src/pages/api/admin/crud/(tables)/clients/(functions)/run-client-setup.ts b/src/pages/api/admin/crud/(tables)/clients/(functions)/run-client-setup.ts new file mode 100644 index 0000000..9650939 --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/(functions)/run-client-setup.ts @@ -0,0 +1,57 @@ +import type { + BUN_SQLITE_WGUI_CLIENTS, + BUN_SQLITE_WGUI_HOSTS, +} from "@/db/types/db"; +import setupWireguardClient from "@/src/functions/backend/setup/setup-wireguard-client"; +import type { TableType, User } from "@/src/types"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; + +type Params = { + client_id?: string | number; + user: User; +}; + +export default async function runClientSetup({ + client_id, + user, +}: Params): Promise { + if (!client_id) { + return { + success: false, + msg: `No client id provided`, + }; + } + + const client_res = await BunSQLite.select< + BUN_SQLITE_WGUI_CLIENTS, + TableType + >({ + table: "clients", + targetId: client_id, + }); + + const client = client_res.singleRes; + + if (!client) { + return { + success: false, + msg: `Client record not found`, + }; + } + + let host: BUN_SQLITE_WGUI_HOSTS | undefined; + + if (client?.host_id) { + const host_res = await BunSQLite.select( + { + table: "hosts", + targetId: client.host_id, + }, + ); + + host = host_res.singleRes || undefined; + } + + return await setupWireguardClient({ client, host, user }); +} \ No newline at end of file diff --git a/src/pages/api/admin/crud/(tables)/clients/del.ts b/src/pages/api/admin/crud/(tables)/clients/del.ts new file mode 100644 index 0000000..b51ea15 --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/del.ts @@ -0,0 +1,63 @@ +import _ from "lodash"; +import type { AdminCrudAPIParams, TableType } from "@/src/types"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; +import checkUserAccess from "@/src/functions/backend/auth/check-user-access"; +import type { + BUN_SQLITE_WGUI_ALL_TYPEDEFS, + BUN_SQLITE_WGUI_CLIENTS, +} from "@/db/types/db"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { ServerQueryParam } from "@moduletrace/bun-sqlite/dist/types"; + +export default async function ( + params: AdminCrudAPIParams, +): Promise { + const { user, user_types, body, id } = params; + + const can_delete_client = checkUserAccess({ + user_types, + // includes: ["admin"], + }); + + if (!can_delete_client.success) { + return { + success: false, + msg: `Can't delete client`, + }; + } + + let query = _.merge< + ServerQueryParam, + ServerQueryParam + >(body?.sql_query || {}, {}); + + const clients_to_delete = await BunSQLite.select< + BUN_SQLITE_WGUI_CLIENTS, + TableType + >({ + table: "clients", + query, + targetId: id, + }); + + if (!clients_to_delete.payload) { + return { + success: false, + msg: `No Media to Delete.`, + }; + } + + for (let i = 0; i < clients_to_delete.payload.length; i++) { + const client = clients_to_delete.payload[i]; + if (!client?.id) continue; + + await BunSQLite.delete({ + table: "clients", + targetId: client.id, + }); + } + + return { + success: true, + }; +} diff --git a/src/pages/api/admin/crud/(tables)/clients/get.ts b/src/pages/api/admin/crud/(tables)/clients/get.ts new file mode 100644 index 0000000..396feea --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/get.ts @@ -0,0 +1,38 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import checkUserAccess from "@/src/functions/backend/auth/check-user-access"; +import type { AdminCrudAPIParams, TableType } from "@/src/types"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; +import _ from "lodash"; + +export default async function ( + params: AdminCrudAPIParams, +): Promise { + const { table, user_types, body, id, query, user } = params; + + let final_sql_query = _.merge(query?.sql_query, body?.sql_query) || {}; + + delete final_sql_query.join; + + const can_user_see_all_clients = checkUserAccess({ + user_types, + includes: ["admin"], + }); + + if (!can_user_see_all_clients.success) { + final_sql_query.query = { + ...final_sql_query.query, + user_id: { + value: user.id, + }, + }; + } + + const GET = await BunSQLite.select({ + table, + query: final_sql_query, + targetId: id, + }); + + return GET; +} diff --git a/src/pages/api/admin/crud/(tables)/clients/index.ts b/src/pages/api/admin/crud/(tables)/clients/index.ts new file mode 100644 index 0000000..430930e --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/index.ts @@ -0,0 +1,29 @@ +import type { AdminCrudAPIParams } from "@/src/types"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; +import _ from "lodash"; +import get from "./get"; +import post from "./post"; +import put from "./put"; +import del from "./del"; + +export default async function ( + params: AdminCrudAPIParams, +): Promise { + const { req, query } = params; + + switch (req.method) { + case "GET": + return await get(params); + case "POST": + return await post(params); + case "PUT": + return await put(params); + case "DELETE": + return await del(params); + + default: + return { + success: false, + }; + } +} diff --git a/src/pages/api/admin/crud/(tables)/clients/post.ts b/src/pages/api/admin/crud/(tables)/clients/post.ts new file mode 100644 index 0000000..2962c9c --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/post.ts @@ -0,0 +1,52 @@ +import type { BUN_SQLITE_WGUI_CLIENTS } from "@/db/types/db"; +import checkUserAccess from "@/src/functions/backend/auth/check-user-access"; +import type { AdminCrudAPIParams } from "@/src/types"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; +import runClientSetup from "./(functions)/run-client-setup"; +import _ from "lodash"; + +export default async function ( + params: AdminCrudAPIParams, +): Promise { + const { table, body, user_types, user } = params; + + let final_insert_data: BUN_SQLITE_WGUI_CLIENTS[] = [ + ...(body?.insert_data || []), + ].map((d) => ({ ...d, user_id: user.id })); + + const is_user_allowed_to_post_any = checkUserAccess({ + // includes: ["admin"], + user_types, + }); + + if (!is_user_allowed_to_post_any.success) { + final_insert_data = final_insert_data.map((fid) => ({ + ...fid, + user_id: user.id, + })); + } + + const POST = await BunSQLite.insert({ + table, + data: final_insert_data, + update_on_duplicate: body?.update_on_duplicate, + }); + + if (POST.success) { + const client_setup_res = await runClientSetup({ + client_id: POST.postInsertReturn?.insertId, + user, + }); + + if (!client_setup_res.success) { + POST.debug = { + ...(POST.debug || {}), + client_setup: client_setup_res, + }; + POST.error = client_setup_res.msg || client_setup_res.error; + } + } + + return POST; +} \ No newline at end of file diff --git a/src/pages/api/admin/crud/(tables)/clients/put.ts b/src/pages/api/admin/crud/(tables)/clients/put.ts new file mode 100644 index 0000000..9d7bd3a --- /dev/null +++ b/src/pages/api/admin/crud/(tables)/clients/put.ts @@ -0,0 +1,56 @@ +import checkUserAccess from "@/src/functions/backend/auth/check-user-access"; +import type { AdminCrudAPIParams } from "@/src/types"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { APIResponseObject } from "@moduletrace/bunext/types"; +import runClientSetup from "./(functions)/run-client-setup"; +import _ from "lodash"; + +export default async function ( + params: AdminCrudAPIParams, +): Promise { + const { table, body, user_types, id, query, user } = params; + + if (!body?.update_data) { + return { + success: false, + msg: `No Update Data`, + }; + } + + const is_user_allowed_to_put = checkUserAccess({ + // includes: ["admin"], + user_types, + }); + + let final_sql_query = _.merge(query?.sql_query, body?.sql_query) || {}; + let targetId = id; + + if (!is_user_allowed_to_put.success) { + final_sql_query = {}; + targetId = user.id; + } + + const PUT = await BunSQLite.update({ + table, + data: body?.update_data, + targetId, + query: final_sql_query, + }); + + if (PUT.success) { + const client_setup_res = await runClientSetup({ + client_id: targetId, + user, + }); + + if (!client_setup_res.success) { + PUT.debug = { + ...(PUT.debug || {}), + client_setup: client_setup_res, + }; + PUT.error = client_setup_res.msg || client_setup_res.error; + } + } + + return PUT; +} \ No newline at end of file diff --git a/src/pages/api/admin/crud/[[...paths]].ts b/src/pages/api/admin/crud/[[...paths]].ts index 16e7a32..28f223b 100644 --- a/src/pages/api/admin/crud/[[...paths]].ts +++ b/src/pages/api/admin/crud/[[...paths]].ts @@ -13,6 +13,7 @@ import type { import type { AdminCrudAPIParams, ApiReqParams, TableType } from "@/src/types"; import userAuth from "@/src/functions/backend/auth/user-auth"; import checkUserAccess from "@/src/functions/backend/auth/check-user-access"; +import clients from "./(tables)/clients"; export const handler: BunextAPIRouteHandler = async ( params, @@ -58,6 +59,8 @@ export const handler: BunextAPIRouteHandler = async ( switch (table) { case "media": return await media(crud_params); + case "clients": + return await clients(crud_params); default: break; diff --git a/src/pages/api/admin/grab-next-available-client-ip.ts b/src/pages/api/admin/grab-next-available-client-ip.ts new file mode 100644 index 0000000..c2cff1d --- /dev/null +++ b/src/pages/api/admin/grab-next-available-client-ip.ts @@ -0,0 +1,55 @@ +import userAuth from "@/src/functions/backend/auth/user-auth"; +import grabNextAvailableClientIPAddress from "@/src/functions/backend/setup/grab-next-available-client-ip"; +import BunSQLite from "@moduletrace/bun-sqlite"; +import type { BUN_SQLITE_WGUI_HOSTS } from "@/db/types/db"; +import type { ApiReqParams, TableType } from "@/src/types"; +import type { + APIResponseObject, + BunextAPIRouteHandler, +} from "@moduletrace/bunext/types"; + +export const handler: BunextAPIRouteHandler = async ( + params, +) => { + const req = params.req; + const body = params.body as ApiReqParams; + + if (req.method !== "POST") { + return { + success: false, + }; + } + + const { user, user_types } = await userAuth({ req }); + + if (!user?.logged_in_status) { + return { + success: false, + msg: `Unauthorized`, + logoutUser: true, + }; + } + + try { + let host: BUN_SQLITE_WGUI_HOSTS | undefined; + + if (body?.host_id) { + const host_res = await BunSQLite.select< + BUN_SQLITE_WGUI_HOSTS, + TableType + >({ + table: "hosts", + targetId: body.host_id, + }); + + host = host_res.singleRes || undefined; + } + + return await grabNextAvailableClientIPAddress({ host }); + } catch (error: any) { + return { + success: false, + msg: error.message, + }; + } +}; \ No newline at end of file diff --git a/src/types/index.ts b/src/types/index.ts index f1cd521..a97eb4e 100755 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -198,6 +198,7 @@ export type ApiReqParams< update_on_duplicate?: boolean; user_id?: string | number | null; dependent_id?: string | number | null; + host_id?: string | number | null; media_base_64?: string; media_base_64_data_url?: string;