From 54e988bd0a7f3dfe3f8a93cf6414cd53e4dc9dbd Mon Sep 17 00:00:00 2001 From: axel Date: Fri, 11 Apr 2025 21:06:52 +0200 Subject: [PATCH] went back to lowdb --- .gitignore | 5 +- .prettierrc | 2 +- db.json | 68 ++++++ package-lock.json | 33 +-- package.json | 2 - .../20250408121716_init/migration.sql | 77 ------- prisma/migrations/migration_lock.toml | 3 - prisma/schema.prisma | 38 ---- src/hooks.server.ts | 53 ++--- src/lib/components/ui/Button.svelte | 8 +- src/lib/server/db/db.ts | 21 -- src/lib/server/db/index.ts | 42 ++++ src/lib/server/db/types/device.ts | 20 +- src/lib/server/db/types/group.ts | 10 +- src/lib/server/db/types/permission.ts | 3 - src/lib/server/db/types/user.ts | 17 +- src/lib/server/sessions.ts | 55 +++-- src/routes/dashboard/devices/+page.server.ts | 38 +--- .../dashboard/devices/[slug]/+page.server.ts | 210 ++++++++---------- src/routes/dashboard/groups/+page.server.ts | 27 +-- src/routes/dashboard/groups/+page.svelte | 8 +- .../dashboard/groups/[slug]/+page.server.ts | 124 +++++------ .../dashboard/groups/[slug]/+page.svelte | 8 +- src/routes/dashboard/users/+page.server.ts | 25 ++- .../dashboard/users/[slug]/+page.server.ts | 155 ++++++------- .../dashboard/users/[slug]/+page.svelte | 18 +- src/routes/login/+page.server.ts | 70 +++--- 27 files changed, 529 insertions(+), 611 deletions(-) create mode 100644 db.json delete mode 100644 prisma/migrations/20250408121716_init/migration.sql delete mode 100644 prisma/migrations/migration_lock.toml delete mode 100644 prisma/schema.prisma delete mode 100644 src/lib/server/db/db.ts create mode 100644 src/lib/server/db/index.ts delete mode 100644 src/lib/server/db/types/permission.ts diff --git a/.gitignore b/.gitignore index 56420a5..6e0715f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,4 @@ vite.config.ts.timestamp-* # Have empty data folder ready to go /data/* -!/data/.gitkeep - -# Generated prisma client -generated/prisma/ \ No newline at end of file +!/data/.gitkeep \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index 3f7802c..9cfdeb9 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,7 +1,7 @@ { "useTabs": true, "singleQuote": true, - "trailingComma": "none", + "trailingComma": "all", "printWidth": 100, "plugins": ["prettier-plugin-svelte"], "overrides": [ diff --git a/db.json b/db.json new file mode 100644 index 0000000..babc996 --- /dev/null +++ b/db.json @@ -0,0 +1,68 @@ +{ + "users": [ + { + "id": "EqWthpxM6dwLpdg6_GMNv", + "name": "admin", + "password": "$2b$10$M5f38oxNH2TbtJrSeR5bi.qgz9n5rhnxrQPh3Y.8GIZaH1Z6MgZDa", + "admin": true, + "groups": [], + "devices": [ + "2PAUDI9gbzwuD8ptcptDM", + "A6u-0SaX5q5s_DzMFf3N1" + ] + }, + { + "id": "l6GVetq1ifjsHmnoy3TrC", + "name": "axel", + "admin": false, + "groups": [ + "2Y1OFiRWu8r50_WBLaB-j" + ], + "devices": [ + "ps8lzN3c2uHcGtqHdmaEz" + ], + "password": "$2b$10$MGb8xG3a4oxIvFq6fiqG8.X8HKS1j8WdjYjc6fgO6W.5s0vvQi8A." + } + ], + "groups": [ + { + "id": "2Y1OFiRWu8r50_WBLaB-j", + "name": "Gr1", + "devices": [ + "2PAUDI9gbzwuD8ptcptDM", + "ps8lzN3c2uHcGtqHdmaEz" + ] + }, + { + "id": "gNaTU4Tdj-6-a8wRyWf21", + "name": "Gr2", + "devices": [] + } + ], + "devices": [ + { + "id": "2PAUDI9gbzwuD8ptcptDM", + "name": "Dev1", + "mac": "00:00:00:00:00:00", + "broadcast": "255.255.255.254", + "port": 9, + "packets": 3 + }, + { + "id": "ps8lzN3c2uHcGtqHdmaEz", + "name": "Dev2", + "mac": "00:00:00:00:00:00", + "broadcast": "255.255.255.255", + "port": 9, + "packets": 3 + }, + { + "id": "A6u-0SaX5q5s_DzMFf3N1", + "name": "Dev3", + "mac": "00:00:00:00:00:00", + "broadcast": "255.255.255.255", + "port": 9, + "packets": 3 + } + ] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6e5c80a..a33b78e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "name": "my-app", "version": "0.0.1", "dependencies": { - "@prisma/client": "^6.5.0", "@types/wake_on_lan": "^0.0.33", "bcryptjs": "^3.0.2", "drizzle-orm": "^0.41.0", @@ -24,7 +23,6 @@ "@tailwindcss/vite": "^4.0.0", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", - "prisma": "^6.5.0", "svelte": "^5.0.0", "svelte-check": "^4.0.0", "tailwindcss": "^4.0.0", @@ -774,6 +772,8 @@ "integrity": "sha512-M6w1Ql/BeiGoZmhMdAZUXHu5sz5HubyVcKukbLs3l0ELcQb8hTUJxtGEChhv4SVJ0QJlwtLnwOLgIRQhpsm9dw==", "hasInstallScript": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "engines": { "node": ">=18.18" }, @@ -794,8 +794,9 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/config/-/config-6.5.0.tgz", "integrity": "sha512-sOH/2Go9Zer67DNFLZk6pYOHj+rumSb0VILgltkoxOjYnlLqUpHPAN826vnx8HigqnOCxj9LRhT6U7uLiIIWgw==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "esbuild": ">=0.12 <1", "esbuild-register": "3.6.0" @@ -805,16 +806,18 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.5.0.tgz", "integrity": "sha512-fc/nusYBlJMzDmDepdUtH9aBsJrda2JNErP9AzuHbgUEQY0/9zQYZdNlXmKoIWENtio+qarPNe/+DQtrX5kMcQ==", - "devOptional": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "optional": true, + "peer": true }, "node_modules/@prisma/engines": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.5.0.tgz", "integrity": "sha512-FVPQYHgOllJklN9DUyujXvh3hFJCY0NX86sDmBErLvoZjy2OXGiZ5FNf3J/C4/RZZmCypZBYpBKEhx7b7rEsdw==", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "6.5.0", "@prisma/engines-version": "6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60", @@ -826,15 +829,17 @@ "version": "6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60.tgz", "integrity": "sha512-iK3EmiVGFDCmXjSpdsKGNqy9hOdLnvYBrJB61far/oP03hlIxrb04OWmDjNTwtmZ3UZdA5MCvI+f+3k2jPTflQ==", - "devOptional": true, - "license": "Apache-2.0" + "license": "Apache-2.0", + "optional": true, + "peer": true }, "node_modules/@prisma/fetch-engine": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.5.0.tgz", "integrity": "sha512-3LhYA+FXP6pqY8FLHCjewyE8pGXXJ7BxZw2rhPq+CZAhvflVzq4K8Qly3OrmOkn6wGlz79nyLQdknyCG2HBTuA==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "6.5.0", "@prisma/engines-version": "6.5.0-73.173f8d54f8d52e692c7e27e72a88314ec7aeff60", @@ -845,8 +850,9 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.5.0.tgz", "integrity": "sha512-xYcvyJwNMg2eDptBYFqFLUCfgi+wZLcj6HDMsj0Qw0irvauG4IKmkbywnqwok0B+k+W+p+jThM2DKTSmoPCkzw==", - "devOptional": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/debug": "6.5.0" } @@ -1841,8 +1847,9 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz", "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==", - "devOptional": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "debug": "^4.3.4" }, @@ -1932,7 +1939,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -2638,9 +2644,10 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.5.0.tgz", "integrity": "sha512-yUGXmWqv5F4PByMSNbYFxke/WbnyTLjnJ5bKr8fLkcnY7U5rU9rUTh/+Fja+gOrRxEgtCbCtca94IeITj4j/pg==", - "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "@prisma/config": "6.5.0", "@prisma/engines": "6.5.0" diff --git a/package.json b/package.json index f8d827d..24eb781 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "@tailwindcss/vite": "^4.0.0", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", - "prisma": "^6.5.0", "svelte": "^5.0.0", "svelte-check": "^4.0.0", "tailwindcss": "^4.0.0", @@ -31,7 +30,6 @@ "vite": "^6.2.5" }, "dependencies": { - "@prisma/client": "^6.5.0", "@types/wake_on_lan": "^0.0.33", "bcryptjs": "^3.0.2", "drizzle-orm": "^0.41.0", diff --git a/prisma/migrations/20250408121716_init/migration.sql b/prisma/migrations/20250408121716_init/migration.sql deleted file mode 100644 index 2b6a6c9..0000000 --- a/prisma/migrations/20250408121716_init/migration.sql +++ /dev/null @@ -1,77 +0,0 @@ --- CreateTable -CREATE TABLE "User" ( - "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - "name" TEXT NOT NULL, - "password" TEXT NOT NULL, - "admin" BOOLEAN NOT NULL DEFAULT false -); - --- CreateTable -CREATE TABLE "Group" ( - "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - "name" TEXT NOT NULL -); - --- CreateTable -CREATE TABLE "Device" ( - "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - "name" TEXT NOT NULL, - "mac" TEXT NOT NULL, - "broadcast" TEXT NOT NULL DEFAULT '255.255.255.255', - "port" INTEGER NOT NULL DEFAULT 9, - "packets" INTEGER NOT NULL DEFAULT 3 -); - --- CreateTable -CREATE TABLE "_GroupToUser" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL, - CONSTRAINT "_GroupToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT "_GroupToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE -); - --- CreateTable -CREATE TABLE "_DeviceToUser" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL, - CONSTRAINT "_DeviceToUser_A_fkey" FOREIGN KEY ("A") REFERENCES "Device" ("id") ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT "_DeviceToUser_B_fkey" FOREIGN KEY ("B") REFERENCES "User" ("id") ON DELETE CASCADE ON UPDATE CASCADE -); - --- CreateTable -CREATE TABLE "_DeviceToGroup" ( - "A" INTEGER NOT NULL, - "B" INTEGER NOT NULL, - CONSTRAINT "_DeviceToGroup_A_fkey" FOREIGN KEY ("A") REFERENCES "Device" ("id") ON DELETE CASCADE ON UPDATE CASCADE, - CONSTRAINT "_DeviceToGroup_B_fkey" FOREIGN KEY ("B") REFERENCES "Group" ("id") ON DELETE CASCADE ON UPDATE CASCADE -); - --- CreateIndex -CREATE UNIQUE INDEX "User_name_key" ON "User"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "Group_name_key" ON "Group"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "Device_name_key" ON "Device"("name"); - --- CreateIndex -CREATE UNIQUE INDEX "Device_mac_key" ON "Device"("mac"); - --- CreateIndex -CREATE UNIQUE INDEX "_GroupToUser_AB_unique" ON "_GroupToUser"("A", "B"); - --- CreateIndex -CREATE INDEX "_GroupToUser_B_index" ON "_GroupToUser"("B"); - --- CreateIndex -CREATE UNIQUE INDEX "_DeviceToUser_AB_unique" ON "_DeviceToUser"("A", "B"); - --- CreateIndex -CREATE INDEX "_DeviceToUser_B_index" ON "_DeviceToUser"("B"); - --- CreateIndex -CREATE UNIQUE INDEX "_DeviceToGroup_AB_unique" ON "_DeviceToGroup"("A", "B"); - --- CreateIndex -CREATE INDEX "_DeviceToGroup_B_index" ON "_DeviceToGroup"("B"); diff --git a/prisma/migrations/migration_lock.toml b/prisma/migrations/migration_lock.toml deleted file mode 100644 index e1640d1..0000000 --- a/prisma/migrations/migration_lock.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Please do not edit this file manually -# It should be added in your version-control system (e.g., Git) -provider = "sqlite" \ No newline at end of file diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index 1c178c6..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,38 +0,0 @@ -// This is your Prisma schema file, -// learn more about it in the docs: https://pris.ly/d/prisma-schema - -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "sqlite" - url = "file:../data/db.sqlite" -} - -model User { - id Int @id @default(autoincrement()) - name String @unique - password String - admin Boolean @default(false) - groups Group[] - devices Device[] -} - -model Group { - id Int @id @default(autoincrement()) - name String @unique - users User[] - devices Device[] -} - -model Device { - id Int @id @default(autoincrement()) - name String @unique - mac String @unique - broadcast String @default("255.255.255.255") - port Int @default(9) - packets Int @default(3) - users User[] - groups Group[] -} diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 2cca2fc..adfc00b 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,36 +1,39 @@ -import { prisma } from "$lib/server/db/db"; -import type { ServerInit } from "@sveltejs/kit"; -import bcrypt from "bcryptjs"; -import { nanoid } from "nanoid"; -import { writeFileSync } from "fs"; -import { Guard } from "$lib/server/guard"; -import { getUserFromSession } from "$lib/server/sessions"; +import { db } from '$lib/server/db'; +import { Guard } from '$lib/server/guard'; +import { getUserFromSession } from '$lib/server/sessions'; +import type { ServerInit } from '@sveltejs/kit'; +import bcrypt from 'bcryptjs'; +import { writeFileSync } from 'fs'; +import { nanoid } from 'nanoid'; export const init: ServerInit = async () => { - const anyUser = await prisma.user.findFirst(); + const anyUser = db.data.users[0]; - if (!anyUser) { - const pass = nanoid(); + if (!anyUser) { + const pass = nanoid(); - await prisma.user.create({ - data: { - name: "admin", - password: bcrypt.hashSync(pass, 10), - admin: true - } - }); + await db.update(({ users }) => { + users.push({ + id: nanoid(), + name: 'admin', + password: bcrypt.hashSync(pass, 10), + admin: true, + groups: [], + devices: [], + }); + }); - console.log(`default admin password: ${pass}`); - console.log("saved to ./default_admin_pass.txt, don't share it and change it asap"); + console.log(`default admin password: ${pass}`); + console.log("saved to ./default_admin_pass.txt, don't share it and change it asap"); - writeFileSync("./data/default_admin_pass.txt", pass); - } + writeFileSync('./data/default_admin_pass.txt', pass); + } }; export async function handle({ event, resolve }) { - const { cookies, locals } = event; + const { cookies, locals } = event; - locals.guard = new Guard(await getUserFromSession(cookies.get("session"))); + locals.guard = new Guard(await getUserFromSession(cookies.get('session'))); - return await resolve(event); -}; \ No newline at end of file + return await resolve(event); +} diff --git a/src/lib/components/ui/Button.svelte b/src/lib/components/ui/Button.svelte index c8a2b85..b946989 100644 --- a/src/lib/components/ui/Button.svelte +++ b/src/lib/components/ui/Button.svelte @@ -20,8 +20,10 @@ ...others }: Props = $props(); - const baseClasses = "block flex items-center text-sm px-4 py-2 transition cursor-pointer rounded box-border"; - let colorClasses = $state(""); + let baseClasses = $state("block flex items-center text-sm px-4 py-2 cursor-pointer rounded transition-all duration-300 ease-in-out"); + + const defaultColors = "bg-neutral-800 hover:bg-neutral-600 text-white border border-transparent"; + let colorClasses = $state(defaultColors); let fullClasses = $derived(baseClasses + " " + extra + " " + colorClasses); @@ -35,7 +37,7 @@ colorClasses = "bg-emerald-500 hover:bg-emerald-600 text-white border border-transparent"; break; default: - colorClasses= "bg-neutral-800 hover:bg-neutral-600 text-white border border-transparent"; + colorClasses= defaultColors; } } else { switch (color) { diff --git a/src/lib/server/db/db.ts b/src/lib/server/db/db.ts deleted file mode 100644 index adeb689..0000000 --- a/src/lib/server/db/db.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { JSONFilePreset } from "lowdb/node"; -import type { User } from "./types/user"; -import type { Device } from "./types/device"; -import type { Group } from "./types/group"; -import { PrismaClient } from "@prisma/client"; - -export const prisma = new PrismaClient(); - -type Data = { - users: User[], - groups: Group[], - devices: Device[], -}; - -const defaultData: Data = { - users: [], - groups: [], - devices: [], -}; - -//export const db = await JSONFilePreset("./data/db.json", defaultData); \ No newline at end of file diff --git a/src/lib/server/db/index.ts b/src/lib/server/db/index.ts new file mode 100644 index 0000000..ec61cad --- /dev/null +++ b/src/lib/server/db/index.ts @@ -0,0 +1,42 @@ +import { JSONFilePreset } from 'lowdb/node'; +import type { Group } from './types/group'; +import type { User } from './types/user'; +import type { Device } from './types/device'; + +type Data = { + users: User[]; + groups: Group[]; + devices: Device[]; +}; + +export const db = await JSONFilePreset('db.json', { + users: [], + groups: [], + devices: [], +}); + +export function getUsersDevices(userId: string): Device[] { + const user = db.data.users.find((u) => u.id === userId)!; + + if (user.admin) return db.data.devices; + + const userDevices = db.data.devices.filter((d) => user.devices.includes(d.id)); + const userGroups = db.data.groups.filter((g) => user.groups.includes(g.id)); + const groupDevices = userGroups.flatMap((g) => + db.data.devices.filter((d) => g.devices.includes(d.id)), + ); + + // concat and dedupe + return [...new Set([...userDevices, ...groupDevices])]; +} + +/** @deprecated */ +export function assignDefaults(defaults: Partial, obj: any, options = { mutate: false }): T { + for (let k of Object.keys(obj)) { + if (obj[k] === undefined) { + delete obj[k]; + } + } + + return options.mutate ? Object.assign(defaults, obj) : Object.assign({}, defaults, obj); +} diff --git a/src/lib/server/db/types/device.ts b/src/lib/server/db/types/device.ts index 6331a08..57537f0 100644 --- a/src/lib/server/db/types/device.ts +++ b/src/lib/server/db/types/device.ts @@ -1,8 +1,14 @@ export type Device = { - id: string, - name: string, - mac: string, - ip: string, - port: number, - packets: number -} \ No newline at end of file + id: string; + name: string; + mac: string; + broadcast: string; + port: number; + packets: number; +}; + +export const defaultDevice: Partial = { + broadcast: '255.255.255.255', + port: 9, + packets: 3, +}; diff --git a/src/lib/server/db/types/group.ts b/src/lib/server/db/types/group.ts index 15252e4..bce0e08 100644 --- a/src/lib/server/db/types/group.ts +++ b/src/lib/server/db/types/group.ts @@ -1,7 +1,5 @@ -import type { Permission } from "./permission" - export type Group = { - id: string, - name: string, - permissions: { [key: string]: Permission } -} \ No newline at end of file + id: string; + name: string; + devices: string[]; +}; diff --git a/src/lib/server/db/types/permission.ts b/src/lib/server/db/types/permission.ts deleted file mode 100644 index e694e4c..0000000 --- a/src/lib/server/db/types/permission.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type Permission = { - wake: boolean; -} \ No newline at end of file diff --git a/src/lib/server/db/types/user.ts b/src/lib/server/db/types/user.ts index e738a2d..c101276 100644 --- a/src/lib/server/db/types/user.ts +++ b/src/lib/server/db/types/user.ts @@ -1,11 +1,8 @@ -import type { Group } from "./group" -import type { Permission } from "./permission" - export type User = { - id: string, - name: string, - password: string, - admin: boolean - groups: string[], - permissions: { [key: string]: Permission } -} \ No newline at end of file + id: string; + name: string; + password: string; + admin: boolean; + groups: string[]; + devices: string[]; +}; diff --git a/src/lib/server/sessions.ts b/src/lib/server/sessions.ts index 0bdcbf1..8ef512b 100644 --- a/src/lib/server/sessions.ts +++ b/src/lib/server/sessions.ts @@ -1,44 +1,39 @@ -import { nanoid } from "nanoid"; -import { prisma } from "./db/db"; -import type { User } from "./db/types/user"; +import { nanoid } from 'nanoid'; +import { db } from './db'; type SessionData = { - userId: number, - userAgent: string, + userId: string; + userAgent: string; }; const sessions: Map = new Map(); export function createSession(data: SessionData) { - const token = nanoid(); - sessions.set(token, data); - setTimeout(() => sessions.delete(token), 1000 * 60 * 60 * 24); - return token; -}; + const token = nanoid(); + sessions.set(token, data); + setTimeout(() => sessions.delete(token), 1000 * 60 * 60 * 24); + return token; +} export async function getUserFromSession(sessionId?: string) { - if (!sessionId) { - return undefined; - } - - const data = sessions.get(sessionId); + if (!sessionId) { + return undefined; + } - if (!data) { - return undefined; - } + const data = sessions.get(sessionId); - // what in the nested fuck is this shit - // I thought ORMs made it easier but they just make queries more ridiculous - const user = await prisma.user.findUnique({ - where: { - id: data.userId - } - }) ?? undefined; + if (!data) { + return undefined; + } - return user; -}; + // what in the nested fuck is this shit + // I thought ORMs made it easier but they just make queries more ridiculous + const user = await db.data.users.find((u) => u.id === data.userId); + + return user; +} export function deleteSession(sessionId?: string) { - if (!sessionId) return; - sessions.delete(sessionId); -} \ No newline at end of file + if (!sessionId) return; + sessions.delete(sessionId); +} diff --git a/src/routes/dashboard/devices/+page.server.ts b/src/routes/dashboard/devices/+page.server.ts index 461e07c..7efc0a0 100644 --- a/src/routes/dashboard/devices/+page.server.ts +++ b/src/routes/dashboard/devices/+page.server.ts @@ -1,31 +1,9 @@ -import { prisma } from "$lib/server/db/db"; -import type { ServerLoad } from "@sveltejs/kit"; +import { getUsersDevices } from '$lib/server/db'; +import type { ServerLoad } from '@sveltejs/kit'; -export const load: ServerLoad = async ({ locals: { guard} }) => { - const user = guard.requiresAuth().orRedirects().getUser(); - - if (user.admin) { - return { - devices: await prisma.device.findMany(), - } - } - - const userDevices = await prisma.user.findUnique({ - where: { - id: user.id - }, - include: { - devices: true, - groups: { - include: { - devices: true - } - } - } - }); - - return { - devices: userDevices == null ? [] : - userDevices.devices.concat(userDevices.groups.flatMap(group => group.devices)), - } -}; \ No newline at end of file +export const load: ServerLoad = async ({ locals: { guard } }) => { + const user = guard.requiresAuth().orRedirects().getUser(); + return { + devices: getUsersDevices(user.id), + }; +}; diff --git a/src/routes/dashboard/devices/[slug]/+page.server.ts b/src/routes/dashboard/devices/[slug]/+page.server.ts index 15d74ca..00b1b1d 100644 --- a/src/routes/dashboard/devices/[slug]/+page.server.ts +++ b/src/routes/dashboard/devices/[slug]/+page.server.ts @@ -1,141 +1,115 @@ -import { prisma } from '$lib/server/db/db'; +import { db, getUsersDevices } from '$lib/server/db/index.js'; import { fail, redirect, type ServerLoad } from '@sveltejs/kit'; +import { nanoid } from 'nanoid'; import { wake } from 'wake_on_lan'; export const load: ServerLoad = async ({ locals: { guard }, params }) => { - guard.requiresAdmin().orRedirects(); + guard.requiresAdmin().orRedirects(); - const device = await prisma.device.findUnique({ - where: { - id: parseInt(params.slug!) || -1, - } - }); + const device = db.data.devices.find((d) => d.id === params.slug); - if (!device && params.slug !== "new") { - redirect(302, "/dashboard/devices"); - } + if (!device && params.slug !== 'new') { + redirect(302, '/dashboard/devices'); + } - return { - device, - } -} + return { + device, + }; +}; export const actions = { - update: async ({ request, cookies, params, locals: { guard } }) => { - if (guard.requiresAdmin().isFailed()) { - return fail(403); - } + update: async ({ request, cookies, params, locals: { guard } }) => { + if (guard.requiresAdmin().isFailed()) { + return fail(403); + } - const form = await request.formData(); - const name = form.get("name")?.toString(); - const mac = form.get("mac")?.toString(); - const broadcast = form.get("broadcast")?.toString(); - const port = form.get("port")?.toString(); - const packets = form.get("packets")?.toString(); + const form = await request.formData(); + const name = form.get('name')?.toString(); + const mac = form.get('mac')?.toString(); + const broadcast = form.get('broadcast')?.toString(); + const port = form.get('port')?.toString(); + const packets = form.get('packets')?.toString(); - if (!name || !mac) { - // TODO better validation - return { - error: "MISSING_FIELDS" - } - } + if (!name || !mac) { + // TODO better validation + return { + error: 'MISSING_FIELDS', + }; + } - try { - if (params.slug === "new") { - await prisma.device.create({ - data: { - name, - mac, - broadcast, - port: port ? parseInt(port) : undefined, - packets: packets ? parseInt(packets) : undefined - } - }); - } else { - await prisma.device.update({ - where: { - id: parseInt(params.slug) - }, - data: { - name, - mac, - broadcast, - port: port ? parseInt(port) : undefined, - packets: packets ? parseInt(packets) : undefined - } - }); - } - } catch (e: any) { - if (e.code === "P2002") { - return fail(409, { error: "This name or this MAC adress is already in use. Please make sure they are unique." }); - } else { - console.error(e); - return fail(500, { error: "DATABASE_ERROR" }); - } - } + try { + if (params.slug === 'new') { + await db.update(({ devices }) => { + devices.push({ + id: nanoid(), + name, + mac, + broadcast: broadcast ?? '255.255.255.255', + port: port ? parseInt(port) : 9, + packets: packets ? parseInt(packets) : 3, + }); + }); + } else { + await db.update(({ devices }) => { + let dev = devices.find((d) => d.id === params.slug); - redirect(302, "/dashboard/devices"); - }, - delete: async ({ locals: { guard }, params }) => { - if (guard.requiresAdmin().isFailed()) { - return fail(403); - } + if (!dev) { + return; + } - await prisma.device.delete({ - where: { - id: parseInt(params.slug) - } - }); + dev.name = name; + dev.mac = mac; + dev.broadcast = broadcast ?? dev.broadcast; + dev.port = port ? parseInt(port) : dev.port; + dev.packets = packets ? parseInt(packets) : dev.packets; + }); + } + } catch (e: any) { + if (e.code === 'P2002') { + return fail(409, { + error: + 'This name or this MAC adress is already in use. Please make sure they are unique.', + }); + } else { + console.error(e); + return fail(500, { error: 'DATABASE_ERROR' }); + } + } - redirect(302, "/dashboard/devices"); - }, - wake: async ({ params, locals: { guard } }) => { - console.log("Trying to wake " + params.slug); + redirect(302, '/dashboard/devices'); + }, + delete: async ({ locals: { guard }, params }) => { + if (guard.requiresAdmin().isFailed()) { + return fail(403); + } - guard = guard.requiresAuth(); + db.data.devices = db.data.devices.filter((d) => d.id !== params.slug); + db.write(); - if (guard.isFailed()) { - console.log("Failed guard"); - return fail(403); - } + redirect(302, '/dashboard/devices'); + }, + wake: async ({ params, locals: { guard } }) => { + console.log('Trying to wake ' + params.slug); - const userDevices = await prisma.user.findUnique({ - where: { - id: guard.getUser().id - }, - include: { - devices: true, - groups: { - include: { - devices: true - } - } - } - }); + guard = guard.requiresAuth(); - if (!userDevices) { - console.log("Failed to find user devices"); - return fail(403); - } + if (guard.isFailed()) { + console.log('Failed guard'); + return fail(403); + } - let deviceId = parseInt(params.slug); + const device = getUsersDevices(guard.getUser().id).find((d) => d.id === params.slug); - if (isNaN(deviceId)) { - return fail(400); - } + if (!device) { + return fail(404); + } - const device = userDevices.devices.find(d => d.id === deviceId) ?? userDevices.groups.flatMap(g => g.devices).find(d => d.id === deviceId); + console.log('Trying to wake ' + device.name); - if (!device) { - return fail(404); - } - - console.log("Trying to wake " + device.name); - - wake(device.mac, { - address: device.broadcast, - port: device.port, - num_packets: device.packets - }, () => {}); - } -} \ No newline at end of file + wake(device.mac, { + address: device.broadcast, + port: device.port, + num_packets: device.packets, + }); + }, +}; diff --git a/src/routes/dashboard/groups/+page.server.ts b/src/routes/dashboard/groups/+page.server.ts index 31990b5..7d6cd03 100644 --- a/src/routes/dashboard/groups/+page.server.ts +++ b/src/routes/dashboard/groups/+page.server.ts @@ -1,15 +1,16 @@ -import { prisma } from "$lib/server/db/db"; -import { type ServerLoad } from "@sveltejs/kit"; +import { db } from '$lib/server/db'; +import { type ServerLoad } from '@sveltejs/kit'; export const load: ServerLoad = async ({ locals: { guard } }) => { - guard.requiresAdmin().orRedirects(); - - return { - groups: await prisma.group.findMany({ - include: { - users: true, - devices: true, - } - }), - } -}; \ No newline at end of file + guard.requiresAdmin().orRedirects(); + return { + groups: db.data.groups, + userCounts: db.data.groups.reduce( + (acc, group) => { + acc[group.id] = db.data.users.filter((u) => u.groups.includes(group.id)).length; + return acc; + }, + {} as Record, + ), + }; +}; diff --git a/src/routes/dashboard/groups/+page.svelte b/src/routes/dashboard/groups/+page.svelte index 39029e9..a0fe243 100644 --- a/src/routes/dashboard/groups/+page.svelte +++ b/src/routes/dashboard/groups/+page.svelte @@ -1,9 +1,9 @@ @@ -19,7 +19,7 @@ {:else}
{#each data.groups as group} - + {#snippet actionsSnippet()} {#if data.user.admin} diff --git a/src/routes/dashboard/users/+page.server.ts b/src/routes/dashboard/users/+page.server.ts index f2e20a9..661cd2d 100644 --- a/src/routes/dashboard/users/+page.server.ts +++ b/src/routes/dashboard/users/+page.server.ts @@ -1,15 +1,16 @@ -import { prisma } from "$lib/server/db/db"; -import type { ServerLoad } from "@sveltejs/kit"; +import { db } from '$lib/server/db'; +import type { User } from '$lib/server/db/types/user'; +import type { ServerLoad } from '@sveltejs/kit'; export const load: ServerLoad = async ({ locals: { guard } }) => { - guard.requiresAdmin().orRedirects(); + guard.requiresAdmin().orRedirects(); - return { - users: await prisma.user.findMany({ - include: { - groups: true, - devices: true - } - }), - } -}; \ No newline at end of file + return { + users: db.data.users.map((u) => { + let safeUser = structuredClone(u) as Partial; + delete safeUser['password']; + + return safeUser; + }), + }; +}; diff --git a/src/routes/dashboard/users/[slug]/+page.server.ts b/src/routes/dashboard/users/[slug]/+page.server.ts index 3e0d3f7..191ce34 100644 --- a/src/routes/dashboard/users/[slug]/+page.server.ts +++ b/src/routes/dashboard/users/[slug]/+page.server.ts @@ -1,88 +1,91 @@ -import { prisma } from "$lib/server/db/db"; -import { fail, redirect, type Actions } from "@sveltejs/kit"; -import bcrypt from "bcryptjs"; +import { db } from '$lib/server/db'; +import type { User } from '$lib/server/db/types/user.js'; +import { fail, redirect, type Actions } from '@sveltejs/kit'; +import bcrypt from 'bcryptjs'; +import { nanoid } from 'nanoid'; export const load = async ({ locals: { guard }, params }) => { - guard.requiresAdmin().orRedirects(); + guard.requiresAdmin().orRedirects(); - const user = await prisma.user.findUnique({ - where: { - id: parseInt(params.slug!) || -1, - }, - include: { - groups: true, - devices: true - } - }); + let user = db.data.users.find((u) => u.id === params.slug) as Partial; - if (!user && params.slug !== "new") { - redirect(302, "/dashboard/users"); - } + if (!user && params.slug !== 'new') { + redirect(302, '/dashboard/users'); + } - return { - user, - groups: await prisma.group.findMany(), - devices: await prisma.device.findMany(), - } + if (user) { + user = structuredClone(user); + delete user['password']; + } + + return { + user, + groups: db.data.groups, + devices: db.data.devices, + }; }; export const actions: Actions = { - update: async ({ request, locals: { guard }, params }) => { - if (guard.requiresAdmin().isFailed()) { - return fail(403); - } + update: async ({ request, locals: { guard }, params }) => { + if (guard.requiresAdmin().isFailed()) { + return fail(403); + } - const form = await request.formData(); - const name = form.get("name")?.toString(); - const admin = form.get("admin")?.toString() === "on"; - const password = form.get("password")?.toString() ?? ""; - const groups = form.getAll("groups").map(g => ({ id: parseInt(g.toString()) })); - const devices = form.getAll("devices").map(d => ({ id: parseInt(d.toString()) })); + const form = await request.formData(); + const name = form.get('name')?.toString(); + const admin = form.get('admin')?.toString() === 'on'; + const password = form.get('password')?.toString() ?? ''; + const groups = form.getAll('groups').map((g) => g.toString()); + const devices = form.getAll('devices').map((d) => d.toString()); - if (!name) { - // TODO better validation - return { - error: "MISSING_FIELDS" - } - } + if (!name) { + // TODO better validation + return { + error: 'MISSING_FIELDS', + }; + } - if (params.slug === "new") { - if (password.length < 4) { - return { - error: "PASSWORD_TOO_WEAK" - } - } + if (params.slug === 'new') { + if (password.length < 4) { + return { + error: 'PASSWORD_TOO_WEAK', + }; + } - await prisma.user.create({ - data: { - name, - password: bcrypt.hashSync(password, 10), - admin, - groups: { - connect: groups - }, - devices: { - connect: devices - } - } - }); - } else { - await prisma.user.update({ - where: { - id: parseInt(params.slug!) || -1, - }, - data: { - name, - admin, - groups: { - set: groups - }, - devices: { - set: devices - }, - password: password.length > 0 ? bcrypt.hashSync(password, 10) : undefined - } - }); - } - } -}; \ No newline at end of file + await db.update(({ users }) => { + users.push({ + id: nanoid(), + name, + admin, + groups, + devices, + password: bcrypt.hashSync(password, 10), + }); + }); + } else { + await db.update(({ users }) => { + let user = users.find((u) => u.id === params.slug); + + if (!user) { + return; + } + + user.name = name; + user.admin = admin; + user.groups = groups; + user.devices = devices; + if (password.length > 0) { + user.password = bcrypt.hashSync(password, 10); + } + }); + } + }, + delete: async ({ locals: { guard }, params }) => { + if (guard.requiresAdmin().isFailed()) { + return fail(403); + } + + db.data.users = db.data.users.filter((u) => u.id !== params.slug); + db.write(); + }, +}; diff --git a/src/routes/dashboard/users/[slug]/+page.svelte b/src/routes/dashboard/users/[slug]/+page.svelte index 090fc67..0725a79 100644 --- a/src/routes/dashboard/users/[slug]/+page.svelte +++ b/src/routes/dashboard/users/[slug]/+page.svelte @@ -1,12 +1,12 @@ @@ -39,7 +39,7 @@ data={data.groups.map(g => ({ value: g.id.toString(), name: g.name, - selected: data.user?.groups.find(ug => ug.id === g.id) ? true : false }))}/> + selected: data.user?.groups?.find(ug => ug === g.id) ? true : false }))}/> ({ value: d.id.toString(), name: d.name, - selected: data.user?.devices.find(ud => ud.id === d.id) ? true : false }))}/> + selected: data.user?.devices?.find(ud => ud === d.id) ? true : false }))}/>
diff --git a/src/routes/login/+page.server.ts b/src/routes/login/+page.server.ts index 144017a..83514fc 100644 --- a/src/routes/login/+page.server.ts +++ b/src/routes/login/+page.server.ts @@ -1,48 +1,48 @@ +import { db } from '$lib/server/db'; import { createSession, getUserFromSession } from '$lib/server/sessions'; import { redirect } from '@sveltejs/kit'; -import type { Actions } from './$types'; -import { prisma } from '$lib/server/db/db'; import bcrypt from 'bcryptjs'; +import type { Actions } from './$types'; export const actions = { default: async ({ cookies, request }) => { if (await getUserFromSession(cookies.get('session'))) { - redirect(302, "/dashboard"); - } + redirect(302, '/dashboard'); + } - const data = await request.formData(); - const username = data.get("username")?.toString(); - const password = data.get("password")?.toString(); + const data = await request.formData(); + const username = data.get('username')?.toString(); + const password = data.get('password')?.toString(); - if (!username || !password) { - return { - error: "MISSING_CREDENTIALS" - } - } + if (!username || !password) { + return { + error: 'MISSING_CREDENTIALS', + }; + } - const user = await prisma.user.findUnique({ - where: { - name: username - } - }); + const user = db.data.users.find((u) => u.name === username); - if (!user || !bcrypt.compareSync(password, user.password)) { - return { - error: "INVALID_CREDENTIALS" - } - } + if (!user || !bcrypt.compareSync(password, user.password)) { + return { + error: 'INVALID_CREDENTIALS', + }; + } - cookies.set("session", createSession({ - userAgent: request.headers.get("user-agent") ?? "UNKNOWN", - userId: user.id - }), { - path: "/", - httpOnly: true, - secure: true, - sameSite: true, - maxAge: 60 * 60 * 24, - }); + cookies.set( + 'session', + createSession({ + userAgent: request.headers.get('user-agent') ?? 'UNKNOWN', + userId: user.id, + }), + { + path: '/', + httpOnly: true, + secure: true, + sameSite: true, + maxAge: 60 * 60 * 24, + }, + ); - redirect(302, "/dashboard"); - } -} satisfies Actions; \ No newline at end of file + redirect(302, '/dashboard'); + }, +} satisfies Actions;