feat(frontend): audit log

This commit is contained in:
sam 2024-12-26 16:33:32 -05:00
parent 49e9eabea0
commit 53006ea313
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
11 changed files with 385 additions and 1 deletions

View file

@ -58,6 +58,13 @@
@{user.username}
</NavLink>
</NavItem>
{#if user.role === "ADMIN" || user.role === "MODERATOR"}
<NavItem>
<NavLink href="/admin" active={page.url.pathname.startsWith(`/admin`)}>
Administration
</NavLink>
</NavItem>
{/if}
<NavItem>
<NavLink href="/settings" active={page.url.pathname.startsWith("/settings")}>
{$t("nav.settings")}

View file

@ -0,0 +1,8 @@
<script lang="ts">
import type { AuditLogEntity } from "$api/models/moderation";
type Props = { entity: AuditLogEntity };
let { entity }: Props = $props();
</script>
<strong>{entity.username}</strong> <span class="text-secondary">({entity.id})</span>

View file

@ -0,0 +1,50 @@
<script lang="ts">
import type { AuditLogEntry } from "$api/models/moderation";
import { idTimestamp } from "$lib";
import { renderMarkdown } from "$lib/markdown";
import { DateTime } from "luxon";
import AuditLogEntity from "./AuditLogEntity.svelte";
type Props = { entry: AuditLogEntry };
let { entry }: Props = $props();
let reason = $derived(renderMarkdown(entry.reason));
let date = $derived(idTimestamp(entry.id).toLocaleString(DateTime.DATETIME_MED));
</script>
<svelte:head>
<title>Audit log</title>
</svelte:head>
<div class="card my-1 p-2">
<h6 class="d-flex">
<span class="flex-grow-1">
<AuditLogEntity entity={entry.moderator} />
{#if entry.type === "IGNORE_REPORT"}
ignored a report
{:else if entry.type === "WARN_USER" || entry.type === "WARN_USER_AND_CLEAR_PROFILE"}
warned
{:else if entry.type === "SUSPEND_USER"}
suspended
{:else}
(unknown action <code>{entry.type}</code>)
{/if}
{#if entry.target_user}
<AuditLogEntity entity={entry.target_user} />
{/if}
{#if entry.target_member}
for member <AuditLogEntity entity={entry.target_member} />
{/if}
</span>
<small class="text-secondary">{date}</small>
</h6>
{#if reason}
<details>
<summary>Reason</summary>
{@html reason}
</details>
{:else}
<em>(no reason given)</em>
{/if}
</div>

View file

@ -0,0 +1,17 @@
<script lang="ts">
import type { Snippet } from "svelte";
type Props = { title: string; onlyNumber?: boolean; children: Snippet };
let { title, onlyNumber = true, children }: Props = $props();
</script>
<div class="col-md">
<div class="card">
<div class="card-body">
<h5 class="card-title">{title}</h5>
<p class="card-text text-center" class:fs-1={onlyNumber}>
{@render children()}
</p>
</div>
</div>
</div>