Add MineGeo gameplay systems and interface

This commit is contained in:
2026-10-10 10:27:47 +05:00
parent bf01d9801d
commit 9af71c85c2
47 changed files with 9954 additions and 93 deletions

View File

@@ -0,0 +1,247 @@
import assert from "node:assert/strict";
import { randomUUID, randomBytes } from "node:crypto";
import { createClient } from "@supabase/supabase-js";
process.loadEnvFile(".env.local");
const origin = process.argv[2] || "https://minegeo.vercel.app";
const db = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.SUPABASE_SECRET_KEY,
{ auth: { persistSession: false, autoRefreshToken: false } },
);
const accounts = [],
maps = [];
const checked = (r) => {
if (r.error) throw new Error(r.error.message);
return r.data;
};
async function request(
account,
path,
body,
method = body === undefined ? "GET" : "POST",
status = 200,
) {
const response = await fetch(`${origin}/api/v1/${path}`, {
method,
headers: {
origin,
"content-type": "application/json",
...(account?.cookie ? { cookie: account.cookie } : {}),
},
...(body === undefined ? {} : { body: JSON.stringify(body) }),
signal: AbortSignal.timeout(60000),
});
const data = await response.json();
assert.equal(response.status, status, `${path}: ${JSON.stringify(data)}`);
return data;
}
async function account(role) {
const email = `admin-permissions-${randomUUID()}@example.com`,
password = randomBytes(24).toString("base64url");
const { user } = checked(
await db.auth.admin.createUser({
email,
password,
email_confirm: true,
user_metadata: { display_name: `Permissions ${role} fixture` },
}),
);
const fixture = { id: user.id, cookie: "" };
accounts.push(fixture);
checked(
await db.from("profiles").insert({
id: user.id,
role,
display_name: `Permissions ${role} fixture`,
}),
);
const response = await fetch(`${origin}/api/v1/auth`, {
method: "POST",
headers: { origin, "content-type": "application/json" },
body: JSON.stringify({
action: "login",
email,
password,
next: "/moderation",
}),
});
assert.equal(response.status, 200, "Fixture login failed");
fixture.cookie = response.headers
.getSetCookie()
.map((value) => value.split(";")[0])
.join("; ");
assert.ok(fixture.cookie, "Login did not set a session cookie");
return fixture;
}
try {
const player = await account("contributor"),
moderator = await account("moderator"),
admin = await account("admin"),
missing = randomUUID();
const bounds = { minX: 0, minZ: 0, maxX: 64, maxZ: 64 };
for (const state of ["review", "unpublished"]) {
const map = checked(
await db
.from("datasets")
.insert({
owner_id: player.id,
name: `Permissions ${state} fixture`,
source: "plugin",
bounds,
state,
panorama_count: 5,
})
.select("id")
.single(),
);
maps.push(map.id);
checked(
await db.from("dataset_inputs").insert({
dataset_id: map.id,
validated: true,
manifest: {
format: "minegeo-dataset/v1",
minecraftVersion: "1.21.11",
dimension: "minecraft:overworld",
source: "plugin",
name: "Permissions map fixture",
description: "Disposable permission verification",
serverName: "Fixture server",
north: "-z",
bounds,
viewpoints: Array.from({ length: 5 }, (_, i) => ({
id: `p${i}`,
x: i * 4,
y: 64,
z: i * 4,
})),
assets: [
{ path: "terrain.json.gz", sha256: "a".repeat(64), bytes: 1 },
],
},
}),
);
}
await request(player, "moderation", undefined, "GET", 403);
const queue = await request(moderator, "moderation");
assert.equal(queue.role, "moderator");
assert.deepEqual(queue.reports, []);
assert.deepEqual(queue.appeals, []);
assert.ok(
queue.maps.every(
(m) =>
m.state === "review" ||
(m.state === "published" && m.update_state === "review"),
),
);
assert.ok(queue.maps.some((m) => m.id === maps[0]));
assert.ok(!queue.maps.some((m) => m.id === maps[1]));
assert.ok(
(await request(moderator, `moderation/${maps[0]}/panoramas`)).locations
.length === 5,
);
await request(
moderator,
`moderation/${maps[1]}/panoramas`,
undefined,
"GET",
403,
);
for (const actor of [player, moderator]) {
for (const [path, body, method] of [
["moderation/users", undefined, "GET"],
[
`moderation/users/${player.id}`,
{ prefix: "Spoof", icon: "star" },
"PATCH",
],
["moderation/settings", { betaBadgeEnabled: false }, "PATCH"],
[
`moderation/appeals/${missing}`,
{ decision: "approve", reason: "A valid reason here." },
"POST",
],
[`moderation/reports/${missing}/panoramas`, undefined, "GET"],
[
`reports/${missing}`,
{ decision: "confirm", reason: "A valid reason here." },
"PATCH",
],
["moderation", { datasetId: maps[0], decision: "unpublish" }, "POST"],
])
await request(actor, path, body, method, 403);
}
await request(moderator, "moderation", {
datasetId: maps[0],
decision: "reject",
reason: "Returned by the permission verification fixture.",
});
assert.equal(
checked(
await db.from("datasets").select("state").eq("id", maps[0]).single(),
).state,
"rejected",
);
const full = await request(admin, "moderation");
assert.equal(full.role, "admin");
assert.ok(full.maps.some((m) => m.id === maps[1]));
assert.equal(
(await request(admin, `moderation/users?q=${player.id}`)).users[0].id,
player.id,
);
await request(
admin,
`moderation/users/${player.id}`,
{ prefix: "Builder", icon: "gem" },
"PATCH",
);
assert.equal(
(await request(player, "profile")).profile.custom_prefix,
"Builder",
);
await request(
admin,
`moderation/users/${player.id}`,
{ prefix: null, icon: "star" },
"PATCH",
);
await request(
admin,
"moderation/settings",
{ betaBadgeEnabled: "invalid" },
"PATCH",
400,
);
await request(
admin,
`reports/${missing}`,
{ decision: "dismiss", reason: "A valid reason here." },
"PATCH",
400,
);
await request(
admin,
`moderation/appeals/${missing}`,
{ decision: "approve", reason: "A valid reason here." },
"POST",
400,
);
for (const actor of [player, moderator, admin])
await request(actor, "profile", { role: "admin" }, "PATCH", 400);
assert.equal((await request(admin, "profile")).profile.role, "admin");
console.log(
"Production permissions passed: signed-in players denied, moderator queue restricted, pending panoramas and feedback work, admin controls available, role spoofing denied.",
);
} finally {
if (maps.length)
checked(await db.from("review_decisions").delete().in("dataset_id", maps));
for (const id of maps)
checked(await db.from("datasets").delete().eq("id", id));
for (const fixture of accounts) {
if (fixture.cookie)
await request(fixture, "auth/logout", {}).catch(() => {});
checked(await db.from("profiles").delete().eq("id", fixture.id));
checked(await db.auth.admin.deleteUser(fixture.id));
}
console.log("Disposable permission fixtures removed.");
}