Files
shd.build/src/routes/admin/audit/+page.server.ts
T

48 lines
3.1 KiB
TypeScript

import { requirePermission } from '$lib/server/auth/authorization';
import { getSessionUser } from '$lib/server/auth/session';
import { getDatabase } from '$lib/server/database';
import { getPagination } from '$lib/server/pagination';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ cookies, url }) => {
await requirePermission(await getSessionUser(cookies), 'audit.view');
const database = await getDatabase();
const query = url.searchParams.get('q')?.trim().slice(0, 120) ?? '';
const category = url.searchParams.get('category')?.trim() ?? '';
const action = url.searchParams.get('action')?.trim() ?? '';
const conditions: string[] = [];
const args: unknown[] = [];
if (query) {
conditions.push(`(audit_log.entity_id LIKE ? ESCAPE '\\' COLLATE NOCASE
OR audit_log.before_json LIKE ? ESCAPE '\\' COLLATE NOCASE
OR audit_log.after_json LIKE ? ESCAPE '\\' COLLATE NOCASE
OR users.username LIKE ? ESCAPE '\\' COLLATE NOCASE
OR user_profiles.display_name LIKE ? ESCAPE '\\' COLLATE NOCASE)`);
const pattern = `%${query.replaceAll('%', '\\%').replaceAll('_', '\\_')}%`;
args.push(pattern, pattern, pattern, pattern, pattern);
}
if (category === 'user') conditions.push("audit_log.entity_type IN ('user','user_access','user_moderation','identity')");
else if (category === 'access_policy') conditions.push("audit_log.entity_type IN ('role','role_management')");
else if (category) { conditions.push('audit_log.entity_type=?'); args.push(category); }
if (action) { conditions.push('audit_log.action=?'); args.push(action); }
const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
const [total, categories, actions, summary] = await Promise.all([
(await database.prepare(`SELECT COUNT(*) AS total FROM audit_log
JOIN users ON users.id=audit_log.actor_id LEFT JOIN user_profiles ON user_profiles.user_id=users.id ${where}`)).get(...args),
(await database.prepare('SELECT entity_type,COUNT(*) AS count FROM audit_log GROUP BY entity_type ORDER BY entity_type')).all(),
(await database.prepare('SELECT action,COUNT(*) AS count FROM audit_log GROUP BY action ORDER BY action')).all(),
(await database.prepare(`SELECT COUNT(*) AS total,
SUM(CASE WHEN entity_type='game_data' THEN 1 ELSE 0 END) AS game_data,
SUM(CASE WHEN entity_type IN ('user','user_access','user_moderation','identity') THEN 1 ELSE 0 END) AS users,
SUM(CASE WHEN entity_type IN ('role','role_management') THEN 1 ELSE 0 END) AS access
FROM audit_log`)).get()
]);
const pagination = getPagination(url, Number(total?.total ?? 0));
const entries = await (await database.prepare(`SELECT audit_log.*,
COALESCE(user_profiles.display_name,users.username) AS actor_name,users.login_username AS actor_login
FROM audit_log JOIN users ON users.id=audit_log.actor_id
LEFT JOIN user_profiles ON user_profiles.user_id=users.id
${where} ORDER BY audit_log.created_at DESC LIMIT ? OFFSET ?`)).all(...args, pagination.perPage, pagination.offset);
return { entries, categories, actions, summary, pagination, filters: { query, category, action } };
};