fix: badge import uses configured gamedata root for ExternalTexts.json
- import-badge.ts, badges route, and badges edit route now resolve ExternalTexts.json via getGamedataRoot() instead of the hardcoded public/nitro-assets/gamedata/ path - writeBadgeToExternalTexts creates the file (and parent dirs) when missing, so fresh deployments no longer fail with ENOENT - upload-import SQL maker now classifies furni via classifyFurni and generates correct category sub-pages (imp_<catKey>) instead of hardcoded imp_other
This commit is contained in:
1 parent
4d4cbd2211
commit
79b82e0a31
4 files changed
+439
-26
No files matched your search
@@ -3,11 +3,11 @@ import path from "node:path";
|
||||
import { withAdmin } from "@/lib/api-handler";
|
||||
import { apiError, apiOk } from "@/lib/api-response";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { getGamedataRoot } from "@/lib/services/furni-asset-dirs";
|
||||
|
||||
const EXTERNAL_TEXTS_PATH = path.join(
|
||||
process.cwd(),
|
||||
"public/nitro-assets/gamedata/ExternalTexts.json",
|
||||
);
|
||||
function externalTextsPath(gamedataRoot: string): string {
|
||||
return path.join(gamedataRoot, "config", "ExternalTexts.json");
|
||||
}
|
||||
|
||||
/** GET - Read badge name/desc from ExternalTexts.json */
|
||||
export const GET = withAdmin(
|
||||
@@ -16,8 +16,11 @@ export const GET = withAdmin(
|
||||
const code = request.nextUrl.searchParams.get("code")?.toUpperCase();
|
||||
if (!code) return apiError("Missing code", 400);
|
||||
|
||||
const gamedataRoot = await getGamedataRoot();
|
||||
if (!gamedataRoot) return apiError("gamedata_root not configured", 500);
|
||||
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const raw = await fs.readFile(externalTextsPath(gamedataRoot), "utf-8");
|
||||
const texts: Record<string, string> = JSON.parse(raw);
|
||||
|
||||
const name =
|
||||
|
||||
@@ -4,13 +4,13 @@ import { withAdmin } from "@/lib/api-handler";
|
||||
import { apiError, apiOk } from "@/lib/api-response";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { logAudit } from "@/lib/services/audit";
|
||||
import { getGamedataRoot } from "@/lib/services/furni-asset-dirs";
|
||||
import { searchBadges } from "@/lib/services/habboassets";
|
||||
import { importBadgeSynced } from "@/lib/services/import-badge";
|
||||
|
||||
const EXTERNAL_TEXTS_PATH = path.join(
|
||||
process.cwd(),
|
||||
"public/nitro-assets/gamedata/ExternalTexts.json",
|
||||
);
|
||||
function externalTextsPath(gamedataRoot: string): string {
|
||||
return path.join(gamedataRoot, "config", "ExternalTexts.json");
|
||||
}
|
||||
|
||||
// ── Search badges via official Habbo external texts ────────────────
|
||||
export const GET = withAdmin(
|
||||
@@ -33,11 +33,14 @@ export const GET = withAdmin(
|
||||
// Check which badges already exist in ExternalTexts.json
|
||||
const existingCodes = new Set<string>();
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts = JSON.parse(raw);
|
||||
for (const badge of badges) {
|
||||
if (texts[`badge_name_${badge.code}`] !== undefined) {
|
||||
existingCodes.add(badge.code);
|
||||
const gamedataRoot = await getGamedataRoot();
|
||||
if (gamedataRoot) {
|
||||
const raw = await fs.readFile(externalTextsPath(gamedataRoot), "utf-8");
|
||||
const texts = JSON.parse(raw);
|
||||
for (const badge of badges) {
|
||||
if (texts[`badge_name_${badge.code}`] !== undefined) {
|
||||
existingCodes.add(badge.code);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
@@ -1,28 +1,37 @@
|
||||
import { promises as fs } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { db, WebsiteBadges } from "@/lib/db";
|
||||
|
||||
const EXTERNAL_TEXTS_PATH = path.join(
|
||||
process.cwd(),
|
||||
"public/nitro-assets/gamedata/ExternalTexts.json",
|
||||
);
|
||||
import { getGamedataRoot } from "@/lib/services/furni-asset-dirs";
|
||||
|
||||
export type ImportBadgeResult =
|
||||
| { ok: true }
|
||||
| { ok: false; error: string; status: number };
|
||||
|
||||
function externalTextsPath(gamedataRoot: string): string {
|
||||
return path.join(gamedataRoot, "config", "ExternalTexts.json");
|
||||
}
|
||||
|
||||
/** Write badge name/desc into ExternalTexts.json (409 if already present). */
|
||||
export async function writeBadgeToExternalTexts(
|
||||
code: string,
|
||||
name: string,
|
||||
description: string,
|
||||
): Promise<ImportBadgeResult> {
|
||||
const gamedataRoot = await getGamedataRoot();
|
||||
if (!gamedataRoot) {
|
||||
return {
|
||||
ok: false,
|
||||
error: "gamedata_root not configured",
|
||||
status: 500,
|
||||
};
|
||||
}
|
||||
const extPath = externalTextsPath(gamedataRoot);
|
||||
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 raw = await fs.readFile(extPath, "utf-8");
|
||||
texts = JSON.parse(raw) as Record<string, string>;
|
||||
} catch (err) {
|
||||
// File not present yet (fresh deployment) — start with an empty object.
|
||||
@@ -52,12 +61,8 @@ export async function writeBadgeToExternalTexts(
|
||||
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),
|
||||
"utf-8",
|
||||
);
|
||||
await fs.mkdir(path.dirname(extPath), { recursive: true });
|
||||
await fs.writeFile(extPath, JSON.stringify(texts, null, 4), "utf-8");
|
||||
return { ok: true };
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
|
||||
Reference in new issue
Block a user