diff --git a/src/app/admin/logs/_lib/load-ignored-logs.ts b/src/app/admin/logs/_lib/load-ignored-logs.ts new file mode 100644 index 00000000..e9083100 --- /dev/null +++ b/src/app/admin/logs/_lib/load-ignored-logs.ts @@ -0,0 +1,160 @@ +import { redirect } from "next/navigation"; +import { calcPagination, parseListParams } from "@/lib/admin-helpers"; +import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; +import { prisma } from "@/lib/prisma"; + +type ListParamsInput = { + searchParams: Promise>; + defaultPerPage?: number; +}; + +async function requireLogsView() { + const { session, permissions } = await getAdminContext(); + if (!canAccess(permissions, PERMS.LOGS_VIEW, session.user.rank)) { + redirect("/admin"); + } +} + +function parsePageParams( + rawParams: Record, + defaultPerPage: number, +) { + const sp = new URLSearchParams(rawParams); + const parsed = parseListParams(sp); + const perPage = Number(rawParams.perPage) || defaultPerPage; + return { search: parsed.search.trim(), page: parsed.page, perPage }; +} + +export type ChatLogListRow = { + id: number; + username: string; + message: string; + timestamp: number; + roomId: number; +}; + +export async function loadChatLogList({ + searchParams, + defaultPerPage = 50, +}: ListParamsInput) { + await requireLogsView(); + + const rawParams = await searchParams; + const { search, page, perPage } = parsePageParams(rawParams, defaultPerPage); + const offset = (page - 1) * perPage; + const like = `%${search}%`; + + type RawRow = { + roomId: number; + message: string; + timestamp: number; + username: string | null; + }; + + const [rawRows, countRows] = search + ? await Promise.all([ + prisma.$queryRaw` + SELECT c.room_id AS roomId, c.message, c.timestamp, u.username AS username + FROM chatlogs_room c + LEFT JOIN users u ON u.id = c.user_from_id + WHERE c.message LIKE ${like} OR u.username LIKE ${like} + ORDER BY c.timestamp DESC + LIMIT ${perPage} OFFSET ${offset}`, + prisma.$queryRaw<{ count: bigint }[]>` + SELECT COUNT(*) AS count + FROM chatlogs_room c + LEFT JOIN users u ON u.id = c.user_from_id + WHERE c.message LIKE ${like} OR u.username LIKE ${like}`, + ]) + : await Promise.all([ + prisma.$queryRaw` + SELECT c.room_id AS roomId, c.message, c.timestamp, u.username AS username + FROM chatlogs_room c + LEFT JOIN users u ON u.id = c.user_from_id + ORDER BY c.timestamp DESC + LIMIT ${perPage} OFFSET ${offset}`, + prisma.$queryRaw<{ count: bigint }[]>` + SELECT COUNT(*) AS count FROM chatlogs_room`, + ]); + + const total = Number(countRows[0]?.count ?? 0); + const pagination = calcPagination(total, page, perPage); + const rows: ChatLogListRow[] = rawRows.map((row, index) => ({ + id: pagination.offset + index + 1, + username: row.username ?? "-", + message: row.message, + timestamp: row.timestamp, + roomId: row.roomId, + })); + + return { rows, ...pagination }; +} + +export type CommandLogListRow = { + id: number; + username: string; + command: string; + params: string; + timestamp: number; +}; + +export async function loadCommandLogList({ + searchParams, + defaultPerPage = 50, +}: ListParamsInput) { + await requireLogsView(); + + const rawParams = await searchParams; + const { search, page, perPage } = parsePageParams(rawParams, defaultPerPage); + const offset = (page - 1) * perPage; + const like = `%${search}%`; + + type RawRow = { + command: string; + params: string; + timestamp: number; + username: string | null; + }; + + const [rawRows, countRows] = search + ? await Promise.all([ + prisma.$queryRaw` + SELECT c.command, c.params, c.timestamp, u.username AS username + FROM commandlogs c + LEFT JOIN users u ON u.id = c.user_id + WHERE c.command LIKE ${like} + OR c.params LIKE ${like} + OR u.username LIKE ${like} + ORDER BY c.timestamp DESC + LIMIT ${perPage} OFFSET ${offset}`, + prisma.$queryRaw<{ count: bigint }[]>` + SELECT COUNT(*) AS count + FROM commandlogs c + LEFT JOIN users u ON u.id = c.user_id + WHERE c.command LIKE ${like} + OR c.params LIKE ${like} + OR u.username LIKE ${like}`, + ]) + : await Promise.all([ + prisma.$queryRaw` + SELECT c.command, c.params, c.timestamp, u.username AS username + FROM commandlogs c + LEFT JOIN users u ON u.id = c.user_id + ORDER BY c.timestamp DESC + LIMIT ${perPage} OFFSET ${offset}`, + prisma.$queryRaw<{ count: bigint }[]>` + SELECT COUNT(*) AS count FROM commandlogs`, + ]); + + const total = Number(countRows[0]?.count ?? 0); + const pagination = calcPagination(total, page, perPage); + const rows: CommandLogListRow[] = rawRows.map((row, index) => ({ + id: pagination.offset + index + 1, + username: row.username ?? "-", + command: row.command, + params: row.params, + timestamp: row.timestamp, + })); + + return { rows, ...pagination }; +} diff --git a/src/app/admin/logs/chat/page.tsx b/src/app/admin/logs/chat/page.tsx index 5b3dad05..81e7c931 100644 --- a/src/app/admin/logs/chat/page.tsx +++ b/src/app/admin/logs/chat/page.tsx @@ -1,32 +1,13 @@ -import { fetchAdminList } from "@/lib/admin-list"; -import { PERMS } from "@/lib/permissions"; +import { loadChatLogList } from "../_lib/load-ignored-logs"; import { ChatTable } from "./chat-table"; export default async function ChatLogsPage({ - params: paramsPromise, searchParams, }: { params: Promise<{ locale: string }>; searchParams: Promise>; }) { - const result = await fetchAdminList( - { - permission: PERMS.LOGS_VIEW, - model: "chatLog", - searchFields: ["message", "user.username"], - defaultPerPage: 50, - include: { user: { select: { username: true } } }, - mapRow: (l) => ({ - id: l.id, - username: l.user.username, - message: l.message, - timestamp: l.timestamp, - roomId: l.roomId, - }), - }, - paramsPromise, - searchParams, - ); + const result = await loadChatLogList({ searchParams, defaultPerPage: 50 }); return (
diff --git a/src/app/admin/logs/commands/page.tsx b/src/app/admin/logs/commands/page.tsx index 59628e22..a2c0f0ac 100644 --- a/src/app/admin/logs/commands/page.tsx +++ b/src/app/admin/logs/commands/page.tsx @@ -1,32 +1,13 @@ -import { fetchAdminList } from "@/lib/admin-list"; -import { PERMS } from "@/lib/permissions"; +import { loadCommandLogList } from "../_lib/load-ignored-logs"; import { CommandsTable } from "./commands-table"; export default async function CommandLogsPage({ - params: paramsPromise, searchParams, }: { params: Promise<{ locale: string }>; searchParams: Promise>; }) { - const result = await fetchAdminList( - { - permission: PERMS.LOGS_VIEW, - model: "commandLog", - searchFields: ["command", "params", "user.username"], - defaultPerPage: 50, - include: { user: { select: { username: true } } }, - mapRow: (l) => ({ - id: l.id, - username: l.user.username, - command: l.command, - params: l.params, - timestamp: l.timestamp, - }), - }, - paramsPromise, - searchParams, - ); + const result = await loadCommandLogList({ searchParams, defaultPerPage: 50 }); return (