73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
|
|
/**
|
||
|
|
* Admin storage status + connection test. Super-admin only.
|
||
|
|
*
|
||
|
|
* GET /api/v1/admin/storage — current backend + capacity stats
|
||
|
|
* POST /api/v1/admin/storage/test — exercise list/put/get/delete on s3
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { NextResponse } from 'next/server';
|
||
|
|
|
||
|
|
import { withAuth } from '@/lib/api/helpers';
|
||
|
|
import { errorResponse, ForbiddenError } from '@/lib/errors';
|
||
|
|
import { TABLES_WITH_STORAGE_KEYS } from '@/lib/storage/migrate';
|
||
|
|
import { getStorageBackend } from '@/lib/storage';
|
||
|
|
import { S3Backend } from '@/lib/storage/s3';
|
||
|
|
import { db } from '@/lib/db';
|
||
|
|
import { sql } from 'drizzle-orm';
|
||
|
|
|
||
|
|
export const runtime = 'nodejs';
|
||
|
|
|
||
|
|
export const GET = withAuth(async (_req, ctx) => {
|
||
|
|
try {
|
||
|
|
if (!ctx.isSuperAdmin) {
|
||
|
|
throw new ForbiddenError('Super admin only');
|
||
|
|
}
|
||
|
|
const backend = await getStorageBackend();
|
||
|
|
|
||
|
|
// Aggregate row count + total bytes across every storage-bearing table.
|
||
|
|
let fileCount = 0;
|
||
|
|
const totalBytes = 0;
|
||
|
|
for (const tbl of TABLES_WITH_STORAGE_KEYS) {
|
||
|
|
const result = await db.execute(
|
||
|
|
sql.raw(
|
||
|
|
`SELECT COUNT(*)::bigint AS n FROM ${tbl.table} WHERE ${tbl.keyColumn} IS NOT NULL`,
|
||
|
|
),
|
||
|
|
);
|
||
|
|
const rows = (
|
||
|
|
Array.isArray(result) ? result : ((result as { rows?: unknown[] }).rows ?? [])
|
||
|
|
) as Array<{ n: number | string }>;
|
||
|
|
fileCount += Number(rows[0]?.n ?? 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
return NextResponse.json({
|
||
|
|
data: {
|
||
|
|
backend: backend.name,
|
||
|
|
fileCount,
|
||
|
|
totalBytes,
|
||
|
|
tablesTracked: TABLES_WITH_STORAGE_KEYS.map((t) => t.table),
|
||
|
|
},
|
||
|
|
});
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
export const POST = withAuth(async (_req, ctx) => {
|
||
|
|
try {
|
||
|
|
if (!ctx.isSuperAdmin) {
|
||
|
|
throw new ForbiddenError('Super admin only');
|
||
|
|
}
|
||
|
|
const backend = await getStorageBackend();
|
||
|
|
if (!(backend instanceof S3Backend)) {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ ok: false, error: 'Test connection only available for S3 backend' },
|
||
|
|
{ status: 400 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
const result = await backend.healthCheck();
|
||
|
|
return NextResponse.json(result);
|
||
|
|
} catch (error) {
|
||
|
|
return errorResponse(error);
|
||
|
|
}
|
||
|
|
});
|