Add player leaderboard and homepage preview

This commit is contained in:
2026-10-06 15:21:49 +05:00
parent 2bbf5ae2c0
commit 949aa6627a
25 changed files with 2363 additions and 28 deletions

View File

@@ -0,0 +1,137 @@
// Isolated database only; no fixture accounts or scores enter the real board.
import assert from "node:assert/strict";
import { readFile, readdir } from "node:fs/promises";
import { PGlite } from "../.data/sql-verification/node_modules/@electric-sql/pglite/dist/index.js";
const db = new PGlite();
try {
await db.exec(`create role anon; create role authenticated; create role service_role;
create schema auth; create table auth.users(id uuid primary key);
create function auth.uid() returns uuid language sql as $$ select null::uuid $$;
create schema storage; create table storage.buckets(id text primary key,name text,public boolean,file_size_limit bigint);`);
for (const file of (await readdir("supabase/migrations"))
.filter((file) => file.endsWith(".sql"))
.sort()) {
await db.exec(await readFile(`supabase/migrations/${file}`, "utf8"));
}
async function board(difficulty = "all", search = "", page = 1, limit = 25) {
return (
await db.query("select public.player_leaderboard($1,$2,$3,$4) as board", [
difficulty,
search,
page,
limit,
])
).rows[0].board;
}
assert.deepEqual((await board()).entries, []);
assert.equal((await board()).page, 1);
assert.equal((await board()).pages, 1);
const ids = [];
for (const name of ["Alice", "Bob", "Carol", "%_Miner"]) {
const id = (
await db.query(
"insert into auth.users values(gen_random_uuid()) returning id",
)
).rows[0].id;
await db.query(
"insert into public.profiles(id,display_name) values($1,$2)",
[id, name],
);
ids.push(id);
}
const dataset = (
await db.query(
`insert into public.datasets(owner_id,name,source,bounds,state,panorama_count)
values($1,'Leaderboard fixture','plugin','{"minX":0,"minZ":0,"maxX":64,"maxZ":64}','published',5) returning id`,
[ids[0]],
)
).rows[0].id;
const revision = (
await db.query(
"insert into public.revisions(dataset_id,asset_root,manifest) values($1,'fixture','{}') returning id",
[dataset],
)
).rows[0].id;
async function game(
owner,
difficulty,
score,
current = 5,
missingResult = false,
) {
const session = (
await db.query(
"insert into public.game_sessions(revision_id,owner_id,access_hash,difficulty,current_round) values($1,$2,'private-fixture-secret',$3,$4) returning id",
[revision, owner, difficulty, current],
)
).rows[0].id;
for (let round = 0; round < 5; round++) {
await db.query(
"insert into public.game_rounds(session_id,round_number,viewpoint,result) values($1,$2,'{}',$3)",
[
session,
round,
missingResult && round === 4
? null
: JSON.stringify({ score: score / 5 }),
],
);
}
}
await game(ids[0], "easy", 19000);
await game(ids[0], "hard", 23000);
await game(ids[1], "easy", 21000);
await game(ids[1], "hard", 23000);
await game(ids[2], "easy", 20000);
await game(ids[2], "hard", 23000);
await game(ids[2], "hard", 23000);
await game(ids[3], "easy", 5000);
await game(null, "easy", 25000);
await game(ids[0], "normal", 25000, 4);
await game(ids[0], "normal", 25000, 5, true);
const all = await board();
assert.equal(all.total_players, 4);
assert.equal(all.total_games, 8);
assert.deepEqual(
all.entries.map((player) => player.display_name),
["Carol", "Bob", "Alice", "%_Miner"],
);
assert.equal(all.entries[0].average_score, 22000);
assert.equal(all.entries[0].games_played, 3);
assert.deepEqual(
(await board("easy")).leaders.map((player) => player.display_name),
["Bob", "Carol", "Alice"],
);
assert.equal((await board("normal")).total_players, 0);
assert.equal((await board("all", "alice")).entries[0].rank, 3);
assert.equal((await board("all", "%_")).matching_players, 1);
assert.equal((await board("all", "' OR 1=1--")).matching_players, 0);
assert.equal((await board("all", "missing")).pages, 1);
const last = await board("all", "", 999, 2);
assert.equal(last.page, 2);
assert.equal(last.pages, 2);
assert.deepEqual(
last.entries.map((player) => player.rank),
[3, 4],
);
assert.equal((await board("all", "", -1, 2)).page, 1);
assert.equal((await board("all", "", 1, 0)).entries.length, 1);
assert.equal((await board(null, null, null, null)).page, 1);
assert.equal(JSON.stringify(all).includes("private-fixture-secret"), false);
assert.equal(JSON.stringify(all).includes("viewpoint"), false);
for (const role of ["anon", "authenticated", "service_role"]) {
const result = await db.query(
"select has_function_privilege($1,'public.player_leaderboard(text,text,integer,integer)','execute') as allowed",
[role],
);
assert.equal(result.rows[0].allowed, role === "service_role");
}
console.log(
"Leaderboard SQL passed: empty board, completed games, guests, ranking ties, difficulty, literal search, pagination, and server-only permissions.",
);
} finally {
await db.close();
}