feat: implement admin dashboard with site settings, user management, and activity monitoring

This commit is contained in:
LaurensBartelds committed 2026-04-25 00:14:57 +02:00
1 parent 4eeacc38c5
commit 107ebf4d47
5 files changed
+2607 -1579

No files matched your search

+31 -17
View File
@@ -1,4 +1,4 @@
import type Database from 'better-sqlite3'
import type Database from "better-sqlite3";
export function runMigrations(db: Database.Database): void {
db.exec(`
@@ -51,35 +51,49 @@ export function runMigrations(db: Database.Database): void {
CREATE INDEX IF NOT EXISTS idx_saved_exams_user ON saved_exams(user_id);
CREATE INDEX IF NOT EXISTS idx_exam_results_user ON exam_results(user_id);
`)
`);
// ── Add role column if missing (existing databases) ──
const cols = db.prepare(`PRAGMA table_info(users)`).all() as { name: string }[]
if (!cols.some(c => c.name === 'role')) {
db.exec(`ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user'`)
const cols = db.prepare(`PRAGMA table_info(users)`).all() as {
name: string;
}[];
if (!cols.some((c) => c.name === "role")) {
db.exec(`ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user'`);
}
// ── Promote first user to admin if no admins exist ──
const adminCount = db.prepare(`SELECT COUNT(*) AS cnt FROM users WHERE role = 'admin'`).get() as { cnt: number }
const adminCount = db
.prepare(`SELECT COUNT(*) AS cnt FROM users WHERE role = 'admin'`)
.get() as { cnt: number };
if (adminCount.cnt === 0) {
db.prepare(`UPDATE users SET role = 'admin' WHERE id = (SELECT MIN(id) FROM users)`).run()
db.prepare(
`UPDATE users SET role = 'admin' WHERE id = (SELECT MIN(id) FROM users)`,
).run();
}
// ── Seed default settings ──
const defaults: Record<string, string> = {
site_name: 'BrainWave',
max_upload_mb: '5',
allow_guest_mode: 'true',
registration_enabled: 'true',
default_theme: 'light',
maintenance_mode: 'false',
maintenance_message: 'We are currently performing maintenance. Please check back soon.',
}
site_name: "BrainWave",
max_upload_mb: "5",
allow_guest_mode: "true",
registration_enabled: "true",
default_theme: "light",
maintenance_mode: "false",
maintenance_message:
"We are currently performing maintenance. Please check back soon.",
smtp_host: "",
smtp_port: "587",
smtp_user: "",
smtp_pass: "",
smtp_from: "BrainWave <noreply@brainwave.local>",
smtp_secure: "auto",
app_url: "http://localhost:5173",
};
const upsert = db.prepare(`
INSERT INTO site_settings (key, value) VALUES (?, ?)
ON CONFLICT(key) DO NOTHING
`)
`);
for (const [key, value] of Object.entries(defaults)) {
upsert.run(key, value)
upsert.run(key, value);
}
}