From 90c002c91985347ad152190a3179455a039562af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Balogh=20Barnab=C3=A1s?= Date: Tue, 23 Dec 2025 18:34:44 +0100 Subject: [PATCH 1/2] Add leaderboards to admin dashboard pages --- .../dashboard/admin/print/+page.server.ts | 28 +++++++++-- src/routes/dashboard/admin/print/+page.svelte | 39 ++++++++------- .../dashboard/admin/review/+page.server.ts | 47 +++++++++++++++++-- .../dashboard/admin/review/+page.svelte | 41 +++++++++------- .../admin/ysws-review/+page.server.ts | 38 +++++++++++++-- .../dashboard/admin/ysws-review/+page.svelte | 39 ++++++++------- 6 files changed, 174 insertions(+), 58 deletions(-) diff --git a/src/routes/dashboard/admin/print/+page.server.ts b/src/routes/dashboard/admin/print/+page.server.ts index 3b91488..325042a 100644 --- a/src/routes/dashboard/admin/print/+page.server.ts +++ b/src/routes/dashboard/admin/print/+page.server.ts @@ -1,7 +1,7 @@ import { db } from '$lib/server/db/index.js'; -import { project, user, devlog } from '$lib/server/db/schema.js'; +import { project, user, devlog, legionReview } from '$lib/server/db/schema.js'; import { error } from '@sveltejs/kit'; -import { eq, and, sql, ne, inArray } from 'drizzle-orm'; +import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm'; import type { Actions } from './$types'; import { getCurrentlyPrinting } from './utils.server'; @@ -31,13 +31,35 @@ export async function load({ locals }) { .from(user) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users + // Leaderboard: total Legion actions per user + const legionAgg = db + .$with('legionAgg') + .as( + db + .select({ userId: legionReview.userId, legionCnt: sql`COUNT(*)`.as('legionCnt') }) + .from(legionReview) + .groupBy(legionReview.userId) + ); + + const totalExpr = sql`COALESCE(${legionAgg.legionCnt}, 0)`; + + const leaderboard = await db + .with(legionAgg) + .select({ id: user.id, name: user.name, review_count: totalExpr }) + .from(user) + .leftJoin(legionAgg, eq(legionAgg.userId, user.id)) + .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0))) + .orderBy(desc(totalExpr)) + .limit(10); + const currentlyPrinting = await getCurrentlyPrinting(locals.user); return { allProjects, projects, users, - currentlyPrinting + currentlyPrinting, + leaderboard }; } diff --git a/src/routes/dashboard/admin/print/+page.svelte b/src/routes/dashboard/admin/print/+page.svelte index fc8301f..f114333 100644 --- a/src/routes/dashboard/admin/print/+page.svelte +++ b/src/routes/dashboard/admin/print/+page.svelte @@ -123,22 +123,29 @@

Leaderboard

-
- Coming soon! - +
+ {#if data.leaderboard?.length > 0} + + + + + + + + + {#each data.leaderboard as row} + + + + + {/each} + +
PrinterNumber of prints
+ {row.name} + {row.review_count}
+ {:else} +

No printing actions yet.

+ {/if}
diff --git a/src/routes/dashboard/admin/review/+page.server.ts b/src/routes/dashboard/admin/review/+page.server.ts index 1abf3bf..73d788b 100644 --- a/src/routes/dashboard/admin/review/+page.server.ts +++ b/src/routes/dashboard/admin/review/+page.server.ts @@ -1,7 +1,7 @@ import { db } from '$lib/server/db/index.js'; -import { project, user, devlog } from '$lib/server/db/schema.js'; +import { project, user, devlog, t1Review, legionReview, t2Review } from '$lib/server/db/schema.js'; import { error } from '@sveltejs/kit'; -import { eq, and, sql, ne, inArray } from 'drizzle-orm'; +import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm'; import type { Actions } from './$types'; export async function load({ locals }) { @@ -30,10 +30,51 @@ export async function load({ locals }) { .from(user) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users + const t1Agg = db + .$with('t1Agg') + .as( + db + .select({ userId: t1Review.userId, t1Cnt: sql`COUNT(*)`.as('t1Cnt') }) + .from(t1Review) + .groupBy(t1Review.userId) + ); + + const legionAgg = db + .$with('legionAgg') + .as( + db + .select({ userId: legionReview.userId, legionCnt: sql`COUNT(*)`.as('legionCnt') }) + .from(legionReview) + .groupBy(legionReview.userId) + ); + + const t2Agg = db + .$with('t2Agg') + .as( + db + .select({ userId: t2Review.userId, t2Cnt: sql`COUNT(*)`.as('t2Cnt') }) + .from(t2Review) + .groupBy(t2Review.userId) + ); + + const totalExpr = sql`COALESCE(${t1Agg.t1Cnt}, 0) + COALESCE(${legionAgg.legionCnt}, 0) + COALESCE(${t2Agg.t2Cnt}, 0)`; + + const leaderboard = await db + .with(t1Agg, legionAgg, t2Agg) + .select({ id: user.id, name: user.name, review_count: totalExpr }) + .from(user) + .leftJoin(t1Agg, eq(t1Agg.userId, user.id)) + .leftJoin(legionAgg, eq(legionAgg.userId, user.id)) + .leftJoin(t2Agg, eq(t2Agg.userId, user.id)) + .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0))) + .orderBy(desc(totalExpr)) + .limit(10); + return { allProjects, projects, - users + users, + leaderboard }; } diff --git a/src/routes/dashboard/admin/review/+page.svelte b/src/routes/dashboard/admin/review/+page.svelte index 2f5c3e8..558e14f 100644 --- a/src/routes/dashboard/admin/review/+page.svelte +++ b/src/routes/dashboard/admin/review/+page.svelte @@ -111,27 +111,34 @@

Leaderboard

-
- Coming soon! - +
+ {#if data.leaderboard?.length > 0} + + + + + + + + + {#each data.leaderboard as row} + + + + + {/each} + +
ReviewerReviews
+ {row.name} + {row.review_count}
+ {:else} +

No reviews yet.

+ {/if}
-

Projects

+

Projects ({projects.length})

{#if projects.length == 0}
diff --git a/src/routes/dashboard/admin/ysws-review/+page.server.ts b/src/routes/dashboard/admin/ysws-review/+page.server.ts index 64b2711..57ae410 100644 --- a/src/routes/dashboard/admin/ysws-review/+page.server.ts +++ b/src/routes/dashboard/admin/ysws-review/+page.server.ts @@ -1,7 +1,7 @@ import { db } from '$lib/server/db/index.js'; -import { project, user, devlog } from '$lib/server/db/schema.js'; +import { project, user, devlog, t2Review, legionReview } from '$lib/server/db/schema.js'; import { error } from '@sveltejs/kit'; -import { eq, and, sql, ne, inArray } from 'drizzle-orm'; +import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm'; import type { Actions } from './$types'; export async function load({ locals }) { @@ -30,10 +30,42 @@ export async function load({ locals }) { .from(user) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users + // Leaderboard: total reviews per user (T2 + Legion) + const t2Agg = db + .$with('t2Agg') + .as( + db + .select({ userId: t2Review.userId, t2Cnt: sql`COUNT(*)`.as('t2Cnt') }) + .from(t2Review) + .groupBy(t2Review.userId) + ); + + const legionAgg = db + .$with('legionAgg') + .as( + db + .select({ userId: legionReview.userId, legionCnt: sql`COUNT(*)`.as('legionCnt') }) + .from(legionReview) + .groupBy(legionReview.userId) + ); + + const totalExpr = sql`COALESCE(${t2Agg.t2Cnt}, 0) + COALESCE(${legionAgg.legionCnt}, 0)`; + + const leaderboard = await db + .with(t2Agg, legionAgg) + .select({ id: user.id, name: user.name, review_count: totalExpr }) + .from(user) + .leftJoin(t2Agg, eq(t2Agg.userId, user.id)) + .leftJoin(legionAgg, eq(legionAgg.userId, user.id)) + .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0))) + .orderBy(desc(totalExpr)) + .limit(10); + return { allProjects, projects, - users + users, + leaderboard }; } diff --git a/src/routes/dashboard/admin/ysws-review/+page.svelte b/src/routes/dashboard/admin/ysws-review/+page.svelte index 52c948e..57a1dff 100644 --- a/src/routes/dashboard/admin/ysws-review/+page.svelte +++ b/src/routes/dashboard/admin/ysws-review/+page.svelte @@ -111,22 +111,29 @@

Leaderboard

-
- Coming soon! - +
+ {#if data.leaderboard?.length > 0} + + + + + + + + + {#each data.leaderboard as row} + + + + + {/each} + +
ReviewerReviews
+ {row.name} + {row.review_count}
+ {:else} +

No reviews yet.

+ {/if}
From a5225d11d2b79ff8772b3e5f6687adbf0b13a209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Balogh=20Barnab=C3=A1s?= Date: Tue, 23 Dec 2025 18:41:10 +0100 Subject: [PATCH 2/2] Remove legion review aggregation from ysws-review leaderboard --- .../dashboard/admin/print/+page.server.ts | 1 - .../dashboard/admin/ysws-review/+page.server.ts | 17 +++-------------- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/routes/dashboard/admin/print/+page.server.ts b/src/routes/dashboard/admin/print/+page.server.ts index 325042a..050910a 100644 --- a/src/routes/dashboard/admin/print/+page.server.ts +++ b/src/routes/dashboard/admin/print/+page.server.ts @@ -31,7 +31,6 @@ export async function load({ locals }) { .from(user) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users - // Leaderboard: total Legion actions per user const legionAgg = db .$with('legionAgg') .as( diff --git a/src/routes/dashboard/admin/ysws-review/+page.server.ts b/src/routes/dashboard/admin/ysws-review/+page.server.ts index 57ae410..0dbfa55 100644 --- a/src/routes/dashboard/admin/ysws-review/+page.server.ts +++ b/src/routes/dashboard/admin/ysws-review/+page.server.ts @@ -1,5 +1,5 @@ import { db } from '$lib/server/db/index.js'; -import { project, user, devlog, t2Review, legionReview } from '$lib/server/db/schema.js'; +import { project, user, devlog, t2Review } from '$lib/server/db/schema.js'; import { error } from '@sveltejs/kit'; import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm'; import type { Actions } from './$types'; @@ -30,7 +30,6 @@ export async function load({ locals }) { .from(user) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users - // Leaderboard: total reviews per user (T2 + Legion) const t2Agg = db .$with('t2Agg') .as( @@ -40,23 +39,13 @@ export async function load({ locals }) { .groupBy(t2Review.userId) ); - const legionAgg = db - .$with('legionAgg') - .as( - db - .select({ userId: legionReview.userId, legionCnt: sql`COUNT(*)`.as('legionCnt') }) - .from(legionReview) - .groupBy(legionReview.userId) - ); - - const totalExpr = sql`COALESCE(${t2Agg.t2Cnt}, 0) + COALESCE(${legionAgg.legionCnt}, 0)`; + const totalExpr = sql`COALESCE(${t2Agg.t2Cnt}, 0)`; const leaderboard = await db - .with(t2Agg, legionAgg) + .with(t2Agg) .select({ id: user.id, name: user.name, review_count: totalExpr }) .from(user) .leftJoin(t2Agg, eq(t2Agg.userId, user.id)) - .leftJoin(legionAgg, eq(legionAgg.userId, user.id)) .where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0))) .orderBy(desc(totalExpr)) .limit(10);