From 55e5028b093fa11c209a5afb430456103c2fc550 Mon Sep 17 00:00:00 2001 From: Adrian Bonpin Date: Sun, 10 May 2026 01:07:24 +0800 Subject: [PATCH] feat(api): add admin paginated suggestions endpoint --- lib/api/community-suggestions.ts | 62 +++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/lib/api/community-suggestions.ts b/lib/api/community-suggestions.ts index ae6cca5..1040d0d 100644 --- a/lib/api/community-suggestions.ts +++ b/lib/api/community-suggestions.ts @@ -1,7 +1,7 @@ import { Elysia, t } from "elysia" import { db } from "@/lib/db/index" import { communitySuggestions, games, user, suggestionStatusEnum } from "@/lib/db/schema" -import { eq, and, desc } from "drizzle-orm" +import { eq, and, desc, sql, ilike } from "drizzle-orm" import { requireAuth, requireContributorOrAdmin } from "@/lib/auth/guard" const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL @@ -60,6 +60,66 @@ export const communitySuggestionRoutes = new Elysia({ prefix: "/community-suggestions", }) + // Admin list with pagination and filtering + .get( + "/admin", + async ({ query, request, set }) => { + const guard = await requireContributorOrAdmin(request.headers) + if (!guard.ok) { + set.status = guard.status + return { error: guard.error } + } + + const { limit, offset, status } = query + + const conditions = [] + if (status) { + conditions.push(eq(communitySuggestions.status, status as typeof suggestionStatusEnum.enumValues[number])) + } + + const whereClause = conditions.length > 0 ? and(...conditions) : undefined + + const [countResult] = await db + .select({ count: sql`count(*)::int` }) + .from(communitySuggestions) + .leftJoin(games, eq(communitySuggestions.gameId, games.id)) + .leftJoin(user, eq(communitySuggestions.userId, user.id)) + .where(whereClause) + + const data = await db + .select({ + id: communitySuggestions.id, + gameId: communitySuggestions.gameId, + gameTitle: games.title, + fieldName: communitySuggestions.fieldName, + currentValue: communitySuggestions.currentValue, + proposedValue: communitySuggestions.proposedValue, + reason: communitySuggestions.reason, + status: communitySuggestions.status, + createdAt: communitySuggestions.createdAt, + reviewedAt: communitySuggestions.reviewedAt, + reviewNote: communitySuggestions.reviewNote, + userName: user.name, + }) + .from(communitySuggestions) + .leftJoin(games, eq(communitySuggestions.gameId, games.id)) + .leftJoin(user, eq(communitySuggestions.userId, user.id)) + .where(whereClause) + .orderBy(desc(communitySuggestions.createdAt)) + .limit(limit) + .offset(offset) + + return { data, total: countResult.count, limit, offset } + }, + { + query: t.Object({ + limit: t.Number({ default: 20 }), + offset: t.Number({ default: 0 }), + status: t.Optional(t.String()), + }), + }, + ) + // Submit a suggestion .post( "/",