Fix TypeScript errors and implement furniture import ID integrity with 18+ age verification
- Add termsAccepted and ageVerified columns to User table - Update register schema with new boolean fields - Fix register form age verification checkbox (th -> t) - Fix furni-import spriteId declaration order - Fix batch route variable naming (id -> spriteId) - Fix catalog-audit import path and ensure correct types - Hardened import with per-item id conflict checks - Added audit option for FurnitureData.json spriteId conflicts - Updated tagline to include Leeftijdsvereiste: 18+
This commit is contained in:
1 parent
e5ec3c1f06
commit
e76c530e4f
13 files changed
+267
-104
No files matched your search
@@ -16,6 +16,7 @@ import {
|
||||
repairFurniData,
|
||||
repairOrphanedCatalog,
|
||||
} from "./catalog-repair";
|
||||
import { readFurniData } from "./furni-data";
|
||||
import { ensureDirectories } from "./furni-import";
|
||||
import {
|
||||
assetNameCandidates,
|
||||
@@ -118,6 +119,7 @@ export interface AuditSummary {
|
||||
duplicatesMerged: number;
|
||||
duplicateRowsRemoved: number;
|
||||
remappedReferences: number;
|
||||
furniDataIdConflicts: number;
|
||||
}
|
||||
|
||||
export interface CatalogAuditOptions {
|
||||
@@ -128,6 +130,7 @@ export interface CatalogAuditOptions {
|
||||
organizeSql?: boolean;
|
||||
repairFurniData?: boolean;
|
||||
repairStructure?: boolean;
|
||||
checkFurniDataIds?: boolean;
|
||||
}
|
||||
|
||||
export async function runCatalogAudit(
|
||||
@@ -722,6 +725,60 @@ export async function runCatalogAudit(
|
||||
}
|
||||
}
|
||||
|
||||
// ── FurnitureData.json id conflict check ──────────────
|
||||
let furniDataIdConflicts: {
|
||||
classname: string;
|
||||
itemId: number;
|
||||
conflictingId: number;
|
||||
existingClassname: string;
|
||||
}[] = [];
|
||||
if (options?.checkFurniDataIds) {
|
||||
onEvent?.({
|
||||
type: "progress",
|
||||
message: "Checking FurnitureData.json for spriteId conflicts…",
|
||||
});
|
||||
try {
|
||||
const furniData = (await readFurniData()) as Record<
|
||||
string,
|
||||
{ furnitype: Array<Record<string, unknown>> }
|
||||
>;
|
||||
// Build map of id → classname from both sections
|
||||
const idToClassname = new Map<number, string>();
|
||||
for (const section of ["roomitemtypes", "wallitemtypes"] as const) {
|
||||
for (const e of furniData[section]?.furnitype ?? []) {
|
||||
const id = Number(e?.id);
|
||||
const classname = typeof e?.classname === "string" ? e.classname : "";
|
||||
if (!Number.isFinite(id) || id <= 0 || !classname) continue;
|
||||
const existing = idToClassname.get(id);
|
||||
if (existing && existing !== classname) {
|
||||
// Conflict: same id used by different classname
|
||||
furniDataIdConflicts.push({
|
||||
classname,
|
||||
itemId: id,
|
||||
conflictingId: id,
|
||||
existingClassname: existing,
|
||||
});
|
||||
} else if (!existing) {
|
||||
idToClassname.set(id, classname);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Remove duplicates (same classname + id pair counted once)
|
||||
const seen = new Set<string>();
|
||||
furniDataIdConflicts = furniDataIdConflicts.filter((c) => {
|
||||
const key = `${c.classname}:${c.conflictingId}`;
|
||||
if (seen.has(key)) return false;
|
||||
seen.add(key);
|
||||
return true;
|
||||
});
|
||||
} catch (err) {
|
||||
onEvent?.({
|
||||
type: "error",
|
||||
message: `FurnitureData id check failed: ${(err as Error).message}`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onEvent?.({ type: "progress", message: "Comparing with clone sources…" });
|
||||
|
||||
const sources = await listSources();
|
||||
@@ -811,6 +868,7 @@ export async function runCatalogAudit(
|
||||
duplicatesMerged,
|
||||
duplicateRowsRemoved,
|
||||
remappedReferences,
|
||||
furniDataIdConflicts: furniDataIdConflicts.length,
|
||||
};
|
||||
|
||||
onEvent?.({
|
||||
|
||||
Reference in new issue
Block a user