fix: support legacy rank permission schema
CI / check (push) Successful in 27s
CI / release (push) Skipped
CI / deploy (push) Successful in 43s

This commit is contained in:
Simo committed 2026-08-31 21:01:13 +02:00
1 parent 384ede19c4
commit 37ad27c5f3
2 files changed
+60 -31

No files matched your search

+17 -12
View File
@@ -87,8 +87,7 @@ describe("RANK_GENERAL_FIELDS", () => {
});
describe("fetchEmulatorRankForEdit", () => {
it("repairs a missing permission_definitions column before loading an existing rank", async () => {
let hasRankColumn = false;
it("loads permissions from the legacy table when permission_definitions is absent", async () => {
const db = {
execute: async (query: SQL | string) => {
const text = queryText(query);
@@ -105,15 +104,21 @@ describe("fetchEmulatorRankForEdit", () => {
];
}
if (text.includes("FROM information_schema.columns")) {
return [[{ c: hasRankColumn ? 1 : 0 }], []];
return [[], []];
}
if (text.includes("ALTER TABLE permission_definitions")) {
hasRankColumn = true;
return [{ affectedRows: 0 }, []];
}
if (text.includes("FROM permission_definitions")) {
if (!hasRankColumn) throw new Error("Unknown column 'rank_11'");
return [[{ permission_key: "cmd_ban", max_value: 1, value: 0 }], []];
if (text.includes("FROM permissions")) {
return [
[
{
id: 11,
rank_name: "Developer",
level: 11,
cmd_ban: 1,
cmd_owner: 2,
},
],
[],
];
}
throw new Error(`Unexpected query: ${text}`);
},
@@ -126,8 +131,8 @@ describe("fetchEmulatorRankForEdit", () => {
fetchEmulatorRankForEdit(db as never, 11),
).resolves.toMatchObject({
id: 11,
permissions: { cmd_ban: "0" },
permissions: { cmd_ban: "1", cmd_owner: "2" },
permissionMaxValues: { cmd_ban: 1, cmd_owner: 2 },
});
expect(hasRankColumn).toBe(true);
});
});
+43 -19
View File
@@ -124,28 +124,52 @@ export async function fetchEmulatorRankForEdit(
);
if (rankRows.length === 0) return null;
await ensurePermissionRankColumn(db, rankId);
const rankColumn = getRankPermissionColumn(rankId);
const permissionRows = await rawRows<
{
permission_key: string;
max_value: number;
value: number | string | null;
}[]
>(
db,
sql`
SELECT permission_key, max_value, ${sql.raw(quoteIdentifier(rankColumn))} AS value
FROM permission_definitions
ORDER BY permission_key ASC
`,
);
const permissions: Record<string, string> = {};
const permissionMaxValues: Record<string, number> = {};
for (const row of permissionRows) {
permissions[row.permission_key] = String(row.value ?? 0);
permissionMaxValues[row.permission_key] = Number(row.max_value ?? 1);
const definitionColumns = await getTableColumns(db, "permission_definitions");
if (definitionColumns.has(rankColumn)) {
const permissionRows = await rawRows<
{
permission_key: string;
max_value: number;
value: number | string | null;
}[]
>(
db,
sql`
SELECT permission_key, max_value, ${sql.raw(quoteIdentifier(rankColumn))} AS value
FROM permission_definitions
ORDER BY permission_key ASC
`,
);
for (const permission of permissionRows) {
permissions[permission.permission_key] = String(permission.value ?? 0);
permissionMaxValues[permission.permission_key] = Number(
permission.max_value ?? 1,
);
}
} else {
const legacyRows = await rawRows<Record<string, unknown>[]>(
db,
sql`SELECT * FROM permissions WHERE id = ${rankId} LIMIT 1`,
);
for (const [key, value] of Object.entries(legacyRows[0] ?? {})) {
if (
key === "id" ||
RANK_GENERAL_FIELDS.has(key) ||
!VALID_KEY.test(key)
) {
continue;
}
const permissionValue =
typeof value === "string" || typeof value === "number"
? toPermissionValue(value)
: 0;
permissions[key] = String(permissionValue);
permissionMaxValues[key] = Math.max(1, permissionValue);
}
}
const row = rankRows[0];