Fix catalog items missing due to page_id VARCHAR mismatch.
Local Build and Deploy / deploy (push) Successful in 56s
Local Build and Deploy / deploy (push) Successful in 56s
Use raw SQL for counts/loads/creates/moves so Habbo DBs with VARCHAR page_id and no AUTO_INCREMENT still show and persist furni. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
33a8a19820
commit
7bc0845932
6 files changed
+139
-79
No files matched your search
@@ -1,9 +1,11 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { Prisma } from "@/generated/prisma/client";
|
||||
import { requirePermission } from "@/lib/admin/guard";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { allocateCatalogItemId } from "@/lib/services/furni-import";
|
||||
import { rcon } from "@/lib/services/rcon";
|
||||
import { logStaffActivity } from "@/lib/services/staff-activity";
|
||||
|
||||
@@ -63,6 +65,44 @@ function pickAllowed(
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Raw INSERT — catalog_items.id has no AUTO_INCREMENT on real Habbo DBs; page_id is often VARCHAR. */
|
||||
async function insertCatalogItemRow(data: {
|
||||
pageId: number;
|
||||
itemIds: string;
|
||||
catalogName: string;
|
||||
costCredits: number;
|
||||
costPoints: number;
|
||||
pointsType: number;
|
||||
amount: number;
|
||||
orderNumber: number;
|
||||
offerId: number;
|
||||
songId: number;
|
||||
limitedSells: number;
|
||||
limitedStack: number;
|
||||
extradata: string;
|
||||
haveOffer: string;
|
||||
clubOnly: string;
|
||||
}): Promise<number> {
|
||||
const pageIdStr = String(data.pageId);
|
||||
return allocateCatalogItemId(async (nextId) => {
|
||||
await prisma.$executeRaw`
|
||||
INSERT INTO catalog_items (
|
||||
id, page_id, item_ids, catalog_name,
|
||||
cost_credits, cost_points, points_type, amount,
|
||||
order_number, offer_id, song_id,
|
||||
limited_sells, limited_stack, extradata, have_offer, club_only
|
||||
) VALUES (
|
||||
${nextId}, ${pageIdStr}, ${data.itemIds}, ${data.catalogName},
|
||||
${data.costCredits}, ${data.costPoints}, ${data.pointsType}, ${data.amount},
|
||||
${data.orderNumber}, ${data.offerId}, ${data.songId},
|
||||
${data.limitedSells}, ${data.limitedStack}, ${data.extradata},
|
||||
${data.haveOffer}, ${data.clubOnly}
|
||||
)
|
||||
`;
|
||||
return nextId;
|
||||
});
|
||||
}
|
||||
|
||||
export async function createCatalogItem(data: {
|
||||
pageId: number;
|
||||
itemIds: string;
|
||||
@@ -92,19 +132,17 @@ export async function createCatalogItem(data: {
|
||||
catalogName = base?.publicName || base?.itemName || String(firstId);
|
||||
}
|
||||
}
|
||||
const created = await prisma.catalogItems.create({
|
||||
data: { ...data, catalogName },
|
||||
});
|
||||
const id = await insertCatalogItemRow({ ...data, catalogName });
|
||||
await rcon.updateCatalog();
|
||||
await logStaffActivity({
|
||||
staffId: staff.id,
|
||||
action: "catalog_item_create",
|
||||
description: `Created catalog item #${created.id}`,
|
||||
description: `Created catalog item #${id}`,
|
||||
targetType: "catalog_item",
|
||||
targetId: created.id,
|
||||
targetId: id,
|
||||
});
|
||||
revalidatePath("/admin/catalog");
|
||||
return { ok: true as const, data: { id: created.id } };
|
||||
return { ok: true as const, data: { id } };
|
||||
}
|
||||
|
||||
/** Bulk create with one RCON refresh at the end. */
|
||||
@@ -145,24 +183,22 @@ export async function bulkCreateCatalogItems({
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
await prisma.catalogItems.create({
|
||||
data: {
|
||||
pageId,
|
||||
itemIds: String(row.baseId),
|
||||
catalogName: base.publicName || base.itemName || String(row.baseId),
|
||||
costCredits: row.credits ?? 0,
|
||||
costPoints: row.points ?? 0,
|
||||
pointsType: row.pointsType ?? 0,
|
||||
amount: 1,
|
||||
limitedSells: 0,
|
||||
limitedStack: 0,
|
||||
orderNumber: 1,
|
||||
offerId: -1,
|
||||
songId: 0,
|
||||
haveOffer: "1",
|
||||
clubOnly: "0",
|
||||
extradata: "",
|
||||
},
|
||||
await insertCatalogItemRow({
|
||||
pageId,
|
||||
itemIds: String(row.baseId),
|
||||
catalogName: base.publicName || base.itemName || String(row.baseId),
|
||||
costCredits: row.credits ?? 0,
|
||||
costPoints: row.points ?? 0,
|
||||
pointsType: row.pointsType ?? 0,
|
||||
amount: 1,
|
||||
limitedSells: 0,
|
||||
limitedStack: 0,
|
||||
orderNumber: 1,
|
||||
offerId: -1,
|
||||
songId: 0,
|
||||
haveOffer: "1",
|
||||
clubOnly: "0",
|
||||
extradata: "",
|
||||
});
|
||||
created++;
|
||||
} catch {
|
||||
@@ -207,10 +243,15 @@ export async function moveCatalogItems({
|
||||
targetPageId: number;
|
||||
}) {
|
||||
await requirePermission(PERMS.CATALOG_EDIT);
|
||||
await prisma.catalogItems.updateMany({
|
||||
where: { id: { in: ids } },
|
||||
data: { pageId: targetPageId },
|
||||
});
|
||||
if (ids.length === 0) {
|
||||
return { ok: true as const, data: {} };
|
||||
}
|
||||
const pageIdStr = String(targetPageId);
|
||||
await prisma.$executeRaw`
|
||||
UPDATE catalog_items
|
||||
SET page_id = ${pageIdStr}
|
||||
WHERE id IN (${Prisma.join(ids)})
|
||||
`;
|
||||
await rcon.updateCatalog();
|
||||
revalidatePath("/admin/catalog");
|
||||
return { ok: true as const, data: {} };
|
||||
@@ -244,6 +285,17 @@ export async function updateCatalogItem({
|
||||
if (Object.keys(safeCatalog).length === 0 && !baseItem) {
|
||||
return { ok: false as const, error: "No valid fields to update" };
|
||||
}
|
||||
|
||||
// page_id is often VARCHAR — update it via raw SQL when present.
|
||||
const pageIdRaw = safeCatalog.pageId;
|
||||
if (pageIdRaw !== undefined) {
|
||||
const pageIdStr = String(pageIdRaw);
|
||||
await prisma.$executeRaw`
|
||||
UPDATE catalog_items SET page_id = ${pageIdStr} WHERE id = ${id}
|
||||
`;
|
||||
delete safeCatalog.pageId;
|
||||
}
|
||||
|
||||
if (Object.keys(safeCatalog).length > 0) {
|
||||
await prisma.catalogItems.update({
|
||||
where: { id },
|
||||
|
||||
Reference in new issue
Block a user