This commit is contained in:
1 parent
8efd032cc6
commit
df38dccbf1
735 files changed
+128321
-120870
No files matched your search
@@ -4,22 +4,30 @@ import { withAdmin } from "@/lib/api-handler";
|
||||
import { apiError, apiOk } from "@/lib/api-response";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
|
||||
const EXTERNAL_TEXTS_PATH = path.join(process.cwd(), "public/nitro-assets/gamedata/ExternalTexts.json");
|
||||
const EXTERNAL_TEXTS_PATH = path.join(
|
||||
process.cwd(),
|
||||
"public/nitro-assets/gamedata/ExternalTexts.json",
|
||||
);
|
||||
|
||||
/** GET - Read badge name/desc from ExternalTexts.json */
|
||||
export const GET = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async (request) => {
|
||||
const code = request.nextUrl.searchParams.get("code")?.toUpperCase();
|
||||
if (!code) return apiError("Missing code", 400);
|
||||
export const GET = withAdmin(
|
||||
{ permission: PERMS.ASSETS_IMPORT },
|
||||
async (request) => {
|
||||
const code = request.nextUrl.searchParams.get("code")?.toUpperCase();
|
||||
if (!code) return apiError("Missing code", 400);
|
||||
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts: Record<string, string> = JSON.parse(raw);
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts: Record<string, string> = JSON.parse(raw);
|
||||
|
||||
const name = texts[`badge_name_${code}`] ?? texts[`${code}_badge_name`] ?? "";
|
||||
const desc = texts[`badge_desc_${code}`] ?? texts[`${code}_badge_desc`] ?? "";
|
||||
const name =
|
||||
texts[`badge_name_${code}`] ?? texts[`${code}_badge_name`] ?? "";
|
||||
const desc =
|
||||
texts[`badge_desc_${code}`] ?? texts[`${code}_badge_desc`] ?? "";
|
||||
|
||||
return apiOk({ name, desc });
|
||||
} catch {
|
||||
return apiError("Failed to read ExternalTexts.json", 500);
|
||||
}
|
||||
});
|
||||
return apiOk({ name, desc });
|
||||
} catch {
|
||||
return apiError("Failed to read ExternalTexts.json", 500);
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -6,71 +6,95 @@ import { PERMS } from "@/lib/permissions";
|
||||
import { logAudit } from "@/lib/services/audit";
|
||||
import { searchBadges } from "@/lib/services/habboassets";
|
||||
|
||||
const EXTERNAL_TEXTS_PATH = path.join(process.cwd(), "public/nitro-assets/gamedata/ExternalTexts.json");
|
||||
const EXTERNAL_TEXTS_PATH = path.join(
|
||||
process.cwd(),
|
||||
"public/nitro-assets/gamedata/ExternalTexts.json",
|
||||
);
|
||||
|
||||
// ── Search badges via official Habbo external texts ────────────────
|
||||
export const GET = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async (request) => {
|
||||
const search = request.nextUrl.searchParams.get("search") || "";
|
||||
const offset = parseInt(request.nextUrl.searchParams.get("offset") || "0", 10);
|
||||
const allHotels = request.nextUrl.searchParams.get("allHotels") === "1";
|
||||
export const GET = withAdmin(
|
||||
{ permission: PERMS.ASSETS_IMPORT },
|
||||
async (request) => {
|
||||
const search = request.nextUrl.searchParams.get("search") || "";
|
||||
const offset = parseInt(
|
||||
request.nextUrl.searchParams.get("offset") || "0",
|
||||
10,
|
||||
);
|
||||
const allHotels = request.nextUrl.searchParams.get("allHotels") === "1";
|
||||
|
||||
const badges = await searchBadges(search, 100, offset, allHotels ? null : undefined);
|
||||
const badges = await searchBadges(
|
||||
search,
|
||||
100,
|
||||
offset,
|
||||
allHotels ? null : undefined,
|
||||
);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// File not found or invalid - treat all as not imported
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// File not found or invalid - treat all as not imported
|
||||
}
|
||||
|
||||
const enriched = badges.map((badge) => ({
|
||||
...badge,
|
||||
alreadyImported: existingCodes.has(badge.code),
|
||||
}));
|
||||
const enriched = badges.map((badge) => ({
|
||||
...badge,
|
||||
alreadyImported: existingCodes.has(badge.code),
|
||||
}));
|
||||
|
||||
return apiOk({ badges: enriched });
|
||||
});
|
||||
return apiOk({ badges: enriched });
|
||||
},
|
||||
);
|
||||
|
||||
// ── Import a single badge ───────────────────────────────────────────
|
||||
export const POST = withAdmin({ permission: PERMS.ASSETS_IMPORT }, async (request, ctx) => {
|
||||
const body = await request.json();
|
||||
const { code, name, description } = body;
|
||||
export const POST = withAdmin(
|
||||
{ permission: PERMS.ASSETS_IMPORT },
|
||||
async (request, ctx) => {
|
||||
const body = await request.json();
|
||||
const { code, name, description } = body;
|
||||
|
||||
if (!code || !name) return apiError("Missing code or name", 400);
|
||||
if (!code || !name) return apiError("Missing code or name", 400);
|
||||
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts = JSON.parse(raw);
|
||||
try {
|
||||
const raw = await fs.readFile(EXTERNAL_TEXTS_PATH, "utf-8");
|
||||
const texts = JSON.parse(raw);
|
||||
|
||||
const nameKey = `badge_name_${code}`;
|
||||
const descKey = `badge_desc_${code}`;
|
||||
const nameKey = `badge_name_${code}`;
|
||||
const descKey = `badge_desc_${code}`;
|
||||
|
||||
if (texts[nameKey] !== undefined) {
|
||||
return apiError("Badge already exists in ExternalTexts.json", 409);
|
||||
}
|
||||
if (texts[nameKey] !== undefined) {
|
||||
return apiError("Badge already exists in ExternalTexts.json", 409);
|
||||
}
|
||||
|
||||
texts[nameKey] = name;
|
||||
texts[descKey] = description || "";
|
||||
texts[nameKey] = name;
|
||||
texts[descKey] = description || "";
|
||||
|
||||
await fs.writeFile(EXTERNAL_TEXTS_PATH, JSON.stringify(texts, null, 4), "utf-8");
|
||||
} catch (err) {
|
||||
console.warn("[import-badges] Failed to update ExternalTexts.json:", (err as Error).message);
|
||||
return apiError("Failed to update ExternalTexts.json", 500);
|
||||
}
|
||||
await fs.writeFile(
|
||||
EXTERNAL_TEXTS_PATH,
|
||||
JSON.stringify(texts, null, 4),
|
||||
"utf-8",
|
||||
);
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
"[import-badges] Failed to update ExternalTexts.json:",
|
||||
(err as Error).message,
|
||||
);
|
||||
return apiError("Failed to update ExternalTexts.json", 500);
|
||||
}
|
||||
|
||||
logAudit({
|
||||
userId: ctx.session.user.id,
|
||||
action: "badge_import",
|
||||
target: "ExternalTexts",
|
||||
after: { code, name, description },
|
||||
});
|
||||
logAudit({
|
||||
userId: ctx.session.user.id,
|
||||
action: "badge_import",
|
||||
target: "ExternalTexts",
|
||||
after: { code, name, description },
|
||||
});
|
||||
|
||||
return apiOk();
|
||||
});
|
||||
return apiOk();
|
||||
},
|
||||
);
|
||||
Reference in new issue
Block a user