Commit 6956cfff authored by Grant's avatar Grant
Browse files

Merge branch 'feat-audit-log' into 'main'

Audit Log

Closes #56

See merge request sc07/canvas!1
parents 5f57679b caf19b24
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import {
  faCog,
  faHashtag,
  faHome,
  faList,
  faServer,
  faShieldHalved,
  faSquare,
@@ -54,6 +55,12 @@ export const SidebarWrapper = () => {
              isActive={pathname === "/"}
              href="/"
            />
            <SidebarItem
              title="Audit Log"
              icon={<FontAwesomeIcon icon={faList} />}
              isActive={pathname === "/audit"}
              href="/audit"
            />
            <CollapseItems
              icon={<FontAwesomeIcon icon={faChartBar} />}
              title="Stats"
+5 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ import { HomePage } from "./pages/Home/page.tsx";
import { AccountsPage } from "./pages/Accounts/Accounts/page.tsx";
import { ServiceSettingsPage } from "./pages/Service/settings.tsx";
import { ToastContainer } from "react-toastify";
import { AuditLog } from "./pages/AuditLog/auditlog.tsx";

const router = createBrowserRouter(
  [
@@ -28,6 +29,10 @@ const router = createBrowserRouter(
          path: "/service/settings",
          element: <ServiceSettingsPage />,
        },
        {
          path: "/audit",
          element: <AuditLog />,
        },
      ],
    },
  ],
+77 −0
Original line number Diff line number Diff line
import { useEffect, useState } from "react";
import { api, handleError } from "../../lib/utils";
import {
  Table,
  TableBody,
  TableCell,
  TableColumn,
  TableHeader,
  TableRow,
} from "@nextui-org/react";

type AuditLogAction = "BAN_CREATE" | "BAN_UPDATE" | "BAN_DELETE";

type AuditLog = {
  id: number;
  userId: string;
  action: AuditLogAction;
  reason?: string;
  comment?: string;

  banId?: number;

  createdAt: string;
  updatedAt?: string;
};

export const AuditLog = () => {
  const [auditLogs, setAuditLogs] = useState<AuditLog[]>([]);

  useEffect(() => {
    api<{ auditLogs: AuditLog[] }>("/api/admin/audit", "GET").then(
      ({ status, data }) => {
        if (status === 200) {
          if (data.success) {
            setAuditLogs(data.auditLogs);
          } else {
            handleError(status, data);
          }
        } else {
          handleError(status, data);
        }
      }
    );
  }, []);

  return (
    <>
      <h4 className="text-l font-semibold">Audit Log</h4>
      <div className="relative">
        <Table>
          <TableHeader>
            <TableColumn>ID</TableColumn>
            <TableColumn>User ID</TableColumn>
            <TableColumn>Action</TableColumn>
            <TableColumn>Reason</TableColumn>
            <TableColumn>Comment</TableColumn>
            <TableColumn>Created At / Updated At</TableColumn>
          </TableHeader>
          <TableBody>
            {auditLogs.map((log) => (
              <TableRow key={log.id}>
                <TableCell>{log.id}</TableCell>
                <TableCell>{log.userId}</TableCell>
                <TableCell>{log.action}</TableCell>
                <TableCell>{log.reason}</TableCell>
                <TableCell>{log.comment}</TableCell>
                <TableCell>
                  {log.createdAt} / {log.updatedAt}
                </TableCell>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </div>
    </>
  );
};
+28 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ Table User {
  pixels Pixel [not null]
  FactionMember FactionMember [not null]
  Ban Ban
  AuditLog AuditLog [not null]
}

Table Instance {
@@ -109,8 +110,30 @@ Table Ban {
  privateNote String
  publicNote String
  expiresAt DateTime [not null]
  createdAt DateTime [default: `now()`, not null]
  updatedAt DateTime
  user User
  instance Instance
  AuditLog AuditLog [not null]
}

Table AuditLog {
  id Int [pk, increment]
  userId String
  action AuditLogAction [not null]
  reason String
  comment String
  banId Int
  createdAt DateTime [default: `now()`, not null]
  updatedAt DateTime
  user User
  ban Ban
}

Enum AuditLogAction {
  BAN_CREATE
  BAN_UPDATE
  BAN_DELETE
}

Ref: Pixel.userId > User.sub
@@ -130,3 +153,7 @@ Ref: FactionSetting.factionId > Faction.id
Ref: Ban.userId - User.sub

Ref: Ban.instanceId - Instance.id

Ref: AuditLog.userId > User.sub

Ref: AuditLog.banId > Ban.id
 No newline at end of file
+22 −0
Original line number Diff line number Diff line
-- CreateEnum
CREATE TYPE "AuditLogAction" AS ENUM ('BAN_CREATE', 'BAN_UPDATE', 'BAN_DELETE');

-- CreateTable
CREATE TABLE "AuditLog" (
    "id" SERIAL NOT NULL,
    "userId" TEXT,
    "action" "AuditLogAction" NOT NULL,
    "reason" TEXT,
    "comment" TEXT,
    "banId" INTEGER,
    "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMP(3),

    CONSTRAINT "AuditLog_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("sub") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "AuditLog" ADD CONSTRAINT "AuditLog_banId_fkey" FOREIGN KEY ("banId") REFERENCES "Ban"("id") ON DELETE SET NULL ON UPDATE CASCADE;
Loading