From 7ec678ae7d410bcd5b7e2cb2e5e60c898a870ad9 Mon Sep 17 00:00:00 2001 From: Chaoscaot Date: Mon, 1 Dec 2025 18:38:06 +0100 Subject: [PATCH] Add AuditLog --- src/components/moderator/App.svelte | 2 + .../moderator/layout/NavLinks.svelte | 1 + .../moderator/pages/logs/AuditLog.svelte | 235 ++++++++++++++++++ .../moderator/pages/logs/columns.ts | 35 +++ src/components/repo/auditlog.ts | 40 +++ src/components/types/auditlog.ts | 19 ++ 6 files changed, 332 insertions(+) create mode 100644 src/components/moderator/pages/logs/AuditLog.svelte create mode 100644 src/components/moderator/pages/logs/columns.ts create mode 100644 src/components/repo/auditlog.ts create mode 100644 src/components/types/auditlog.ts diff --git a/src/components/moderator/App.svelte b/src/components/moderator/App.svelte index cb0dc13..0d12441 100644 --- a/src/components/moderator/App.svelte +++ b/src/components/moderator/App.svelte @@ -27,6 +27,7 @@ import Event from "@components/moderator/pages/event/Event.svelte"; import Pages from "@components/moderator/pages/pages/Pages.svelte"; import Generator from "@components/moderator/pages/generators/Generator.svelte"; + import AuditLog from "@components/moderator/pages/logs/AuditLog.svelte"; import { Tooltip } from "bits-ui"; const routes: RouteDefinition = { @@ -36,6 +37,7 @@ "/event/:id": Event, "/event/:id/generate": Generator, "/pages": Pages, + "/logs": AuditLog, }; diff --git a/src/components/moderator/layout/NavLinks.svelte b/src/components/moderator/layout/NavLinks.svelte index 1b540e7..f058c3d 100644 --- a/src/components/moderator/layout/NavLinks.svelte +++ b/src/components/moderator/layout/NavLinks.svelte @@ -27,4 +27,5 @@ Players Pages Schematics + Logs diff --git a/src/components/moderator/pages/logs/AuditLog.svelte b/src/components/moderator/pages/logs/AuditLog.svelte new file mode 100644 index 0000000..b436f0a --- /dev/null +++ b/src/components/moderator/pages/logs/AuditLog.svelte @@ -0,0 +1,235 @@ + + +
+
+ + debounce(e.currentTarget.value, (v) => { + fullText = v; + })} + oninput={(e) => + debounce(e.currentTarget.value, (v) => { + fullText = v; + })} + /> + + + + + + + + + + + No Players found :( + + {#each $players.filter((v) => v.name.toLowerCase().includes(playerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} + (actors = actors.includes(player.uuid) ? actors.filter((v) => v !== player.uuid) : [...actors, player.uuid])} + keywords={[player.uuid]} + > + + {player.name} + + {/each} + + + + + + + + + + + + + + No Players found :( + + {#each $players.filter((v) => v.name.toLowerCase().includes(ownerSearch.toLowerCase())).filter((v, i) => i < 50) as player (player.uuid)} + (serverOwner = serverOwner.includes(player.uuid) ? serverOwner.filter((v) => v !== player.uuid) : [...serverOwner, player.uuid])} + keywords={[player.uuid]} + > + + {player.name} + + {/each} + + + + + +
+ +
+
+ +
+ +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + Keine Einträge gefunden. + + {/each} + +
+
+ +
+
+ +
+ + +
+
diff --git a/src/components/moderator/pages/logs/columns.ts b/src/components/moderator/pages/logs/columns.ts new file mode 100644 index 0000000..805cb9e --- /dev/null +++ b/src/components/moderator/pages/logs/columns.ts @@ -0,0 +1,35 @@ +import type { AuditLogEntry } from "@components/types/auditlog"; +import type { ColumnDef } from "@tanstack/table-core"; + +export const columns: ColumnDef[] = [ + { + accessorKey: "id", + header: "ID", + }, + { + accessorKey: "time", + header: "Time", + cell: (info) => new Date(info.getValue()).toLocaleString(), + }, + { + accessorKey: "server", + header: "Server", + }, + { + accessorKey: "serverOwner", + header: "Server Owner", + cell: (info) => info.getValue() || "N/A", + }, + { + accessorKey: "actor", + header: "Spieler", + }, + { + accessorKey: "actionType", + header: "Action Type", + }, + { + accessorKey: "actionText", + header: "Action Text", + }, +]; diff --git a/src/components/repo/auditlog.ts b/src/components/repo/auditlog.ts new file mode 100644 index 0000000..ee2609b --- /dev/null +++ b/src/components/repo/auditlog.ts @@ -0,0 +1,40 @@ +import { derived } from "svelte/store"; +import { fetchWithToken, tokenStore } from "./repo"; +import { PagedAutidLogSchema } from "@components/types/auditlog"; + +export class AuditLogRepo { + async get( + actionText: string | undefined, + serverText: string | undefined, + fullText: string | undefined, + actor: string[] | undefined, + actionType: string[] | undefined, + timeFrom: number | undefined, + timeTo: number | undefined, + serverOwner: string[] | undefined, + velocity: boolean | undefined, + page: number, + pageSize: number, + sorting: string | undefined + ) { + const params = new URLSearchParams(); + if (actionText) params.append("actionText", actionText); + if (serverText) params.append("serverText", serverText); + if (fullText) params.append("fullText", fullText); + if (actor) actor.forEach((a) => params.append("actor", a.toString())); + if (actionType) actionType.forEach((a) => params.append("actionType", a)); + if (timeFrom) params.append("timeGreater", timeFrom.toString()); + if (timeTo) params.append("timeLess", timeTo.toString()); + if (serverOwner) serverOwner.forEach((s) => params.append("serverOwner", s.toString())); + if (velocity !== undefined) params.append("velocity", velocity.toString()); + params.append("page", page.toString()); + params.append("limit", pageSize.toString()); + if (sorting) params.append("sorting", sorting); + + return await fetchWithToken("", `/auditlog?${params.toString()}`) + .then((value) => value.json()) + .then((data) => PagedAutidLogSchema.parse(data)); + } +} + +export const auditLog = derived(tokenStore, ($token) => new AuditLogRepo()); diff --git a/src/components/types/auditlog.ts b/src/components/types/auditlog.ts new file mode 100644 index 0000000..d956980 --- /dev/null +++ b/src/components/types/auditlog.ts @@ -0,0 +1,19 @@ +import { z } from "zod"; + +export const AuditLogEntrySchema = z.object({ + id: z.number(), + time: z.number(), + server: z.string(), + serverOwner: z.string().nullable(), + actor: z.string(), + actionType: z.enum(["JOIN", "LEAVE", "COMMAND", "SENSITIVE_COMMAND", "CHAT", "GUI_OPEN", "GUI_CLOSE", "GUI_CLICK"]), + actionText: z.string(), +}); + +export const PagedAutidLogSchema = z.object({ + entries: z.array(AuditLogEntrySchema), + rows: z.number(), +}); + +export type AuditLogEntry = z.infer; +export type PagedAuditLog = z.infer;