Skip to content

Commit 3d48390

Browse files
committed
fix: BigInt serialization and overlapping admin pages
- Cast COUNT(*) to SIGNED in users query + convert BigInt values to Number - Fix renderAdminServers and renderAdminServerDetail to deactivate all pages before activating their own, preventing multiple pages showing at once
1 parent 4e36b38 commit 3d48390

2 files changed

Lines changed: 17 additions & 8 deletions

File tree

public/js/admin.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,10 @@ function updateAdminNav() {
274274
}
275275

276276
async function renderAdminServers() {
277+
document.querySelectorAll('.admin-page').forEach(p => p.classList.remove('active'));
277278
const el = $a('#admin-page-servers');
278279
if (!el) return;
279280
el.classList.add('active');
280-
const detailPage = $a('#admin-page-server-detail');
281-
if (detailPage) detailPage.classList.remove('active');
282281
el.innerHTML = ahtml`
283282
<div class="page-header">
284283
<h1 class="page-title">All Servers</h1>
@@ -343,10 +342,9 @@ async function renderAdminServers() {
343342
}
344343

345344
async function renderAdminServerDetail(serverId) {
345+
document.querySelectorAll('.admin-page').forEach(p => p.classList.remove('active'));
346346
const detailPage = $a('#admin-page-server-detail');
347-
const listPage = $a('#admin-page-servers');
348347
if (!detailPage) return;
349-
if (listPage) listPage.classList.remove('active');
350348
detailPage.classList.add('active');
351349

352350
detailPage.innerHTML = ahtml`

routes/admin.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,12 +231,14 @@ router.delete('/servers/:id', authenticateToken, requireAdmin, async (req, res)
231231
// ─── Users ──────────────────────────────────────────────
232232
router.get('/users', authenticateToken, requireAdmin, async (req, res) => {
233233
try {
234-
const rows = await query(`
234+
let rows = await query(`
235235
SELECT u.id, u.email, u.username, u.is_admin, u.created_at,
236-
(SELECT COUNT(*) FROM server_meta WHERE user_id = u.id) as server_count
236+
CAST((SELECT COUNT(*) FROM server_meta WHERE user_id = u.id) AS SIGNED) as server_count
237237
FROM users u
238238
ORDER BY u.created_at DESC
239239
`);
240+
// Convert any BigInt values to Number for JSON serialization
241+
rows = rows.map(r => ({ ...r, id: Number(r.id), server_count: Number(r.server_count) }));
240242
res.json({ users: rows });
241243
} catch (err) {
242244
console.error('Admin users list error:', err.message);
@@ -259,11 +261,20 @@ router.get('/users/:id', authenticateToken, requireAdmin, async (req, res) => {
259261
return res.status(404).json({ error: 'User not found' });
260262
}
261263

262-
const user = users[0];
263-
const servers = await query(
264+
let user = users[0];
265+
for (const k of Object.keys(user)) {
266+
if (typeof user[k] === 'bigint') user[k] = Number(user[k]);
267+
}
268+
269+
let servers = await query(
264270
'SELECT * FROM server_meta WHERE user_id = ? ORDER BY created_at DESC',
265271
[userId]
266272
);
273+
for (const s of servers) {
274+
for (const k of Object.keys(s)) {
275+
if (typeof s[k] === 'bigint') s[k] = Number(s[k]);
276+
}
277+
}
267278

268279
const ips = await query(
269280
'SELECT ip_address, created_at FROM user_ips WHERE user_id = ? ORDER BY created_at DESC',

0 commit comments

Comments
 (0)