fix: SQL maker creates wrong categories and badge import fails when ExternalTexts.json missing
- writeSqlMigration now classifies furni via classifyFurni and generates correct category sub-pages (imp_<catKey>) instead of hardcoded imp_other - writeSqlMigration generates idempotent INSERT...SELECT WHERE NOT EXISTS for parent and category catalog_pages, with correct numeric page_id - writeBadgeToExternalTexts creates ExternalTexts.json (and parent dirs) when missing instead of failing with ENOENT
This commit is contained in:
1 parent
1851653afb
commit
4d4cbd2211
3 files changed
+60
-15
No files matched your search
@@ -17,24 +17,42 @@ export async function writeBadgeToExternalTexts(
|
||||
name: string,
|
||||
description: string,
|
||||
): Promise<ImportBadgeResult> {
|
||||
const nameKey = `badge_name_${code}`;
|
||||
const descKey = `badge_desc_${code}`;
|
||||
|
||||
let texts: Record<string, string>;
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts = JSON.parse(raw) as Record<string, string>;
|
||||
|
||||
const nameKey = `badge_name_${code}`;
|
||||
const descKey = `badge_desc_${code}`;
|
||||
|
||||
if (texts[nameKey] !== undefined) {
|
||||
texts = JSON.parse(raw) as Record<string, string>;
|
||||
} catch (err) {
|
||||
// File not present yet (fresh deployment) — start with an empty object.
|
||||
if ((err as NodeJS.ErrnoException).code !== "ENOENT") {
|
||||
console.warn(
|
||||
"[import-badges] Failed to update ExternalTexts.json:",
|
||||
(err as Error).message,
|
||||
);
|
||||
return {
|
||||
ok: false,
|
||||
error: "Badge already exists in ExternalTexts.json",
|
||||
status: 409,
|
||||
error: "Failed to update ExternalTexts.json",
|
||||
status: 500,
|
||||
};
|
||||
}
|
||||
texts = {};
|
||||
}
|
||||
|
||||
texts[nameKey] = name;
|
||||
texts[descKey] = description || "";
|
||||
if (texts[nameKey] !== undefined) {
|
||||
return {
|
||||
ok: false,
|
||||
error: "Badge already exists in ExternalTexts.json",
|
||||
status: 409,
|
||||
};
|
||||
}
|
||||
|
||||
texts[nameKey] = name;
|
||||
texts[descKey] = description || "";
|
||||
|
||||
try {
|
||||
await fs.mkdir(path.dirname(EXTERNAL_TEXTS_PATH), { recursive: true });
|
||||
await fs.writeFile(
|
||||
EXTERNAL_TEXTS_PATH,
|
||||
JSON.stringify(texts, null, 4),
|
||||
|
||||
@@ -62,6 +62,8 @@ vi.mock("@/lib/services/furni-import", () => ({
|
||||
async (insertFn: (nextId: number) => Promise<unknown>) => insertFn(701),
|
||||
),
|
||||
autoPriceFurni: vi.fn(() => ({ credits: 3, points: 0, pointsType: 0 })),
|
||||
CATEGORY_PAGE: {},
|
||||
classifyFurni: vi.fn(() => "other"),
|
||||
ensureDirectories: vi.fn(async () => {
|
||||
const dirs = [
|
||||
assetTargets.swfDir,
|
||||
@@ -76,6 +78,8 @@ vi.mock("@/lib/services/furni-import", () => ({
|
||||
await Promise.all(dirs.map((dir) => fs.mkdir(dir, { recursive: true })));
|
||||
}),
|
||||
getOrCreateCategoryPage: getOrCreateCategoryPageMock,
|
||||
IMPORTED_PAGE_CAPTION: "Imported Furniture",
|
||||
IMPORTED_PAGE_CAPTION_SAVE: "imported_furni",
|
||||
}));
|
||||
|
||||
vi.mock("@/lib/services/swf/nitro-builder", () => ({
|
||||
|
||||
@@ -7,8 +7,12 @@ import { appendFurniEntry, buildFurniEntry } from "@/lib/services/furni-data";
|
||||
import {
|
||||
allocateCatalogItemId,
|
||||
autoPriceFurni,
|
||||
CATEGORY_PAGE,
|
||||
classifyFurni,
|
||||
ensureDirectories,
|
||||
getOrCreateCategoryPage,
|
||||
IMPORTED_PAGE_CAPTION,
|
||||
IMPORTED_PAGE_CAPTION_SAVE,
|
||||
} from "@/lib/services/furni-import";
|
||||
import { parseNitroBundle } from "@/lib/services/swf/nitro-builder";
|
||||
|
||||
@@ -153,6 +157,7 @@ async function writeSqlMigration(params: {
|
||||
interactionType: string;
|
||||
customparams: string;
|
||||
price: { credits: number; points: number; pointsType: number };
|
||||
categoryKey: string;
|
||||
}): Promise<string> {
|
||||
const num = await findNextMigrationNumber();
|
||||
const padded = String(num).padStart(4, "0");
|
||||
@@ -163,11 +168,29 @@ async function writeSqlMigration(params: {
|
||||
fileName,
|
||||
);
|
||||
|
||||
const catKey = params.categoryKey;
|
||||
const captionSave = `imp_${catKey}`;
|
||||
const catInfo = CATEGORY_PAGE[catKey] || CATEGORY_PAGE.other;
|
||||
|
||||
const lines: string[] = [
|
||||
`-- Migration: ${fileName}`,
|
||||
`-- Description: Import furniture "${params.classname}"`,
|
||||
`-- Generated: ${new Date().toISOString()}`,
|
||||
"",
|
||||
`-- Ensure the "Imported Furniture" parent page exists`,
|
||||
`INSERT INTO catalog_pages (caption_save, caption, page_layout, parent_id, min_rank, order_num, icon_image, enabled, visible, includes, page_headline, page_teaser, page_special, page_text1, page_text2, page_text_details, page_text_teaser)`,
|
||||
`SELECT ${escapeSql(IMPORTED_PAGE_CAPTION_SAVE)}, ${escapeSql(IMPORTED_PAGE_CAPTION)}, 'default_3x3', -1, '1', 9999, 263, '1', '1', '', '', '', '', '', '', '', ''`,
|
||||
`WHERE NOT EXISTS (SELECT 1 FROM catalog_pages WHERE caption_save = ${escapeSql(IMPORTED_PAGE_CAPTION_SAVE)});`,
|
||||
"",
|
||||
`-- Ensure the category sub-page exists (${catKey})`,
|
||||
`INSERT INTO catalog_pages (caption_save, caption, page_layout, parent_id, min_rank, order_num, icon_image, enabled, visible, includes, page_headline, page_teaser, page_special, page_text1, page_text2, page_text_details, page_text_teaser)`,
|
||||
`SELECT ${escapeSql(captionSave)}, ${escapeSql(catInfo.label)}, 'default_3x3', p.id, '1', ${catInfo.order}, ${catInfo.icon}, '1', '1', '', '', '', '', '', '', '', ''`,
|
||||
`FROM catalog_pages p`,
|
||||
`WHERE p.caption_save = ${escapeSql(IMPORTED_PAGE_CAPTION_SAVE)}`,
|
||||
` AND NOT EXISTS (SELECT 1 FROM catalog_pages c WHERE c.caption_save = ${escapeSql(captionSave)} AND c.parent_id = p.id);`,
|
||||
"",
|
||||
`SET @next_id = (SELECT COALESCE(MAX(id), 0) + 1 FROM items_base);`,
|
||||
"",
|
||||
`INSERT INTO items_base`,
|
||||
` (id, sprite_id, public_name, item_name, type, width, length, stack_height,`,
|
||||
` allow_stack, allow_sit, allow_lay, allow_walk, interaction_type, customparams)`,
|
||||
@@ -177,13 +200,12 @@ async function writeSqlMigration(params: {
|
||||
` ${params.allowStack}, ${params.cansiton ? "1" : "0"}, ${params.canlayon ? "1" : "0"}, ${params.canstandon ? "1" : "0"},`,
|
||||
` ${escapeSql(params.interactionType)}, ${escapeSql(params.customparams)});`,
|
||||
"",
|
||||
`SET @next_id = LAST_INSERT_ID();`,
|
||||
"",
|
||||
`INSERT INTO catalog_items`,
|
||||
` (id, page_id, item_ids, catalog_name, cost_credits, cost_points, points_type, amount, order_number, offer_id, extradata)`,
|
||||
`VALUES`,
|
||||
` (NULL, ${escapeSql("imp_other")}, @next_id, ${escapeSql(params.classname)},`,
|
||||
` ${params.price.credits}, ${params.price.points}, ${params.price.pointsType}, 1, 1, '-1', '');`,
|
||||
`SELECT (SELECT COALESCE(MAX(id), 0) + 1 FROM catalog_items), p.id, @next_id, ${escapeSql(params.classname)},`,
|
||||
` ${params.price.credits}, ${params.price.points}, ${params.price.pointsType}, 1, 1, '-1', ''`,
|
||||
`FROM catalog_pages p`,
|
||||
`WHERE p.caption_save = ${escapeSql(captionSave)};`,
|
||||
"",
|
||||
];
|
||||
|
||||
@@ -379,6 +401,7 @@ export async function uploadSingleFurni(params: {
|
||||
interactionType: userInteractionType,
|
||||
customparams,
|
||||
price,
|
||||
categoryKey: classifyFurni(classname, itemType),
|
||||
});
|
||||
warnings.push(`SQL migration written: ${sqlFile}`);
|
||||
} catch (err) {
|
||||
|
||||
Reference in new issue
Block a user