Add updateExisting option to furniture import
- Added updateExisting parameter to importSingleFurni and API routes - When updateExisting=true, existing items are updated (catalog price/page) instead of failing - Added catalogUpdated flag to ImportSingleResult - Updates existing catalog entries (price, page) instead of skipping duplicates
This commit is contained in:
1 parent
f89b8a6adf
commit
7ef5038a9e
3 files changed
+48
-15
No files matched your search
@@ -297,6 +297,7 @@ export const POST = withAdmin(
|
||||
type: item.type ?? "flooritem",
|
||||
revision: item.revision ?? 0,
|
||||
category: item.category ?? "unknown",
|
||||
updateExisting: body.updateExisting === true,
|
||||
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
||||
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
||||
iconBaseUrl: source?.iconBaseUrl || undefined,
|
||||
@@ -359,6 +360,7 @@ export const POST = withAdmin(
|
||||
revision,
|
||||
category,
|
||||
sourceId,
|
||||
updateExisting,
|
||||
} = body;
|
||||
|
||||
if (!classname || !name) return apiError("Missing classname or name", 400);
|
||||
@@ -374,6 +376,7 @@ export const POST = withAdmin(
|
||||
type: type ?? "flooritem",
|
||||
revision: revision ?? 0,
|
||||
category: category ?? "unknown",
|
||||
updateExisting: updateExisting === true,
|
||||
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
||||
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
||||
iconBaseUrl: source?.iconBaseUrl || undefined,
|
||||
|
||||
@@ -424,6 +424,7 @@ export async function importSingleFurni(params: {
|
||||
revision: number;
|
||||
category: string;
|
||||
skipFurniDataWrite?: boolean;
|
||||
updateExisting?: boolean;
|
||||
onProgress?: (status: string) => void;
|
||||
/** Per-source SWF download base URL (e.g. "https://virtualc.nl/dcr"). */
|
||||
sourceSwfBaseUrl?: string;
|
||||
@@ -440,6 +441,7 @@ export async function importSingleFurni(params: {
|
||||
revision,
|
||||
category,
|
||||
skipFurniDataWrite,
|
||||
updateExisting,
|
||||
onProgress,
|
||||
sourceSwfBaseUrl,
|
||||
nitroBaseUrl: sourceNitroBaseUrl,
|
||||
@@ -454,28 +456,34 @@ export async function importSingleFurni(params: {
|
||||
.where(eq(ItemsBase.itemName, classname))
|
||||
.limit(1);
|
||||
if (existsByName) {
|
||||
return {
|
||||
ok: false,
|
||||
warnings,
|
||||
error: `Item "${classname}" already exists (id: ${existsByName.id})`,
|
||||
};
|
||||
if (!updateExisting) {
|
||||
return {
|
||||
ok: false,
|
||||
warnings,
|
||||
error: `Item "${classname}" already exists (id: ${existsByName.id})`,
|
||||
};
|
||||
}
|
||||
// Update existing item - fall through to update logic
|
||||
}
|
||||
const [existsById] = await db
|
||||
.select({ itemName: ItemsBase.itemName })
|
||||
.from(ItemsBase)
|
||||
.where(eq(ItemsBase.id, originalId))
|
||||
.limit(1);
|
||||
if (existsById) {
|
||||
return {
|
||||
ok: false,
|
||||
warnings,
|
||||
error: `spriteId ${originalId} already used by "${existsById.itemName}"`,
|
||||
};
|
||||
if (existsById && (!existsByName || existsById.itemName !== classname)) {
|
||||
if (!updateExisting) {
|
||||
return {
|
||||
ok: false,
|
||||
warnings,
|
||||
error: `spriteId ${originalId} already used by "${existsById.itemName}"`,
|
||||
};
|
||||
}
|
||||
// Update existing item - fall through to update logic
|
||||
}
|
||||
|
||||
// ── Check if spriteId already used in FurnitureData.json ──
|
||||
const takenBy = await findFurniDataIdConflict(originalId, classname);
|
||||
if (takenBy) {
|
||||
if (takenBy && !updateExisting) {
|
||||
return {
|
||||
ok: false,
|
||||
warnings,
|
||||
@@ -824,6 +832,7 @@ export async function importSingleFurni(params: {
|
||||
|
||||
// ── Create catalog entry (with duplicate check + category sub-page) ──
|
||||
let catalogItemId: number | null = null;
|
||||
let catalogUpdated = false;
|
||||
try {
|
||||
const itemIdStr = String(spriteId);
|
||||
|
||||
@@ -834,9 +843,28 @@ export async function importSingleFurni(params: {
|
||||
|
||||
if (existingCatalog.length > 0) {
|
||||
catalogItemId = existingCatalog[0].id;
|
||||
warnings.push(
|
||||
`Item already in catalog (catalog_item #${catalogItemId}, page ${existingCatalog[0].page_id}) — skipped duplicate`,
|
||||
);
|
||||
if (updateExisting) {
|
||||
// Update existing catalog entry: price, page, etc.
|
||||
const categoryPageId = await getOrCreateCategoryPage(
|
||||
classname,
|
||||
itemType,
|
||||
);
|
||||
const pageIdStr = String(categoryPageId);
|
||||
const price = autoPriceFurni(classname);
|
||||
await db.execute(sql`
|
||||
UPDATE catalog_items
|
||||
SET page_id = ${pageIdStr}, cost_credits = ${price.credits}, cost_points = ${price.points}, points_type = ${price.pointsType}
|
||||
WHERE id = ${catalogItemId}
|
||||
`);
|
||||
catalogUpdated = true;
|
||||
warnings.push(
|
||||
`Item updated in catalog (catalog_item #${catalogItemId}, page ${categoryPageId})`,
|
||||
);
|
||||
} else {
|
||||
warnings.push(
|
||||
`Item already in catalog (catalog_item #${catalogItemId}, page ${existingCatalog[0].page_id}) — skipped duplicate`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Get or create the right category sub-page based on classname
|
||||
const categoryPageId = await getOrCreateCategoryPage(classname, itemType);
|
||||
@@ -861,6 +889,7 @@ export async function importSingleFurni(params: {
|
||||
ok: true,
|
||||
itemId: spriteId,
|
||||
catalogItemId,
|
||||
catalogUpdated,
|
||||
dimensions: dims,
|
||||
spriteCount: conversionResult?.spriteCount,
|
||||
warnings,
|
||||
|
||||
@@ -93,6 +93,7 @@ export interface ImportSingleResult {
|
||||
ok: boolean;
|
||||
itemId?: number;
|
||||
catalogItemId?: number | null;
|
||||
catalogUpdated?: boolean;
|
||||
dimensions?: { x: number; y: number; z: number };
|
||||
spriteCount?: number;
|
||||
warnings: string[];
|
||||
|
||||
Reference in new issue
Block a user