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",
|
type: item.type ?? "flooritem",
|
||||||
revision: item.revision ?? 0,
|
revision: item.revision ?? 0,
|
||||||
category: item.category ?? "unknown",
|
category: item.category ?? "unknown",
|
||||||
|
updateExisting: body.updateExisting === true,
|
||||||
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
||||||
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
||||||
iconBaseUrl: source?.iconBaseUrl || undefined,
|
iconBaseUrl: source?.iconBaseUrl || undefined,
|
||||||
@@ -359,6 +360,7 @@ export const POST = withAdmin(
|
|||||||
revision,
|
revision,
|
||||||
category,
|
category,
|
||||||
sourceId,
|
sourceId,
|
||||||
|
updateExisting,
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
if (!classname || !name) return apiError("Missing classname or name", 400);
|
if (!classname || !name) return apiError("Missing classname or name", 400);
|
||||||
@@ -374,6 +376,7 @@ export const POST = withAdmin(
|
|||||||
type: type ?? "flooritem",
|
type: type ?? "flooritem",
|
||||||
revision: revision ?? 0,
|
revision: revision ?? 0,
|
||||||
category: category ?? "unknown",
|
category: category ?? "unknown",
|
||||||
|
updateExisting: updateExisting === true,
|
||||||
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
sourceSwfBaseUrl: source?.sourceSwfBaseUrl,
|
||||||
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
nitroBaseUrl: source?.nitroBaseUrl || undefined,
|
||||||
iconBaseUrl: source?.iconBaseUrl || undefined,
|
iconBaseUrl: source?.iconBaseUrl || undefined,
|
||||||
|
|||||||
@@ -424,6 +424,7 @@ export async function importSingleFurni(params: {
|
|||||||
revision: number;
|
revision: number;
|
||||||
category: string;
|
category: string;
|
||||||
skipFurniDataWrite?: boolean;
|
skipFurniDataWrite?: boolean;
|
||||||
|
updateExisting?: boolean;
|
||||||
onProgress?: (status: string) => void;
|
onProgress?: (status: string) => void;
|
||||||
/** Per-source SWF download base URL (e.g. "https://virtualc.nl/dcr"). */
|
/** Per-source SWF download base URL (e.g. "https://virtualc.nl/dcr"). */
|
||||||
sourceSwfBaseUrl?: string;
|
sourceSwfBaseUrl?: string;
|
||||||
@@ -440,6 +441,7 @@ export async function importSingleFurni(params: {
|
|||||||
revision,
|
revision,
|
||||||
category,
|
category,
|
||||||
skipFurniDataWrite,
|
skipFurniDataWrite,
|
||||||
|
updateExisting,
|
||||||
onProgress,
|
onProgress,
|
||||||
sourceSwfBaseUrl,
|
sourceSwfBaseUrl,
|
||||||
nitroBaseUrl: sourceNitroBaseUrl,
|
nitroBaseUrl: sourceNitroBaseUrl,
|
||||||
@@ -454,28 +456,34 @@ export async function importSingleFurni(params: {
|
|||||||
.where(eq(ItemsBase.itemName, classname))
|
.where(eq(ItemsBase.itemName, classname))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
if (existsByName) {
|
if (existsByName) {
|
||||||
return {
|
if (!updateExisting) {
|
||||||
ok: false,
|
return {
|
||||||
warnings,
|
ok: false,
|
||||||
error: `Item "${classname}" already exists (id: ${existsByName.id})`,
|
warnings,
|
||||||
};
|
error: `Item "${classname}" already exists (id: ${existsByName.id})`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// Update existing item - fall through to update logic
|
||||||
}
|
}
|
||||||
const [existsById] = await db
|
const [existsById] = await db
|
||||||
.select({ itemName: ItemsBase.itemName })
|
.select({ itemName: ItemsBase.itemName })
|
||||||
.from(ItemsBase)
|
.from(ItemsBase)
|
||||||
.where(eq(ItemsBase.id, originalId))
|
.where(eq(ItemsBase.id, originalId))
|
||||||
.limit(1);
|
.limit(1);
|
||||||
if (existsById) {
|
if (existsById && (!existsByName || existsById.itemName !== classname)) {
|
||||||
return {
|
if (!updateExisting) {
|
||||||
ok: false,
|
return {
|
||||||
warnings,
|
ok: false,
|
||||||
error: `spriteId ${originalId} already used by "${existsById.itemName}"`,
|
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 ──
|
// ── Check if spriteId already used in FurnitureData.json ──
|
||||||
const takenBy = await findFurniDataIdConflict(originalId, classname);
|
const takenBy = await findFurniDataIdConflict(originalId, classname);
|
||||||
if (takenBy) {
|
if (takenBy && !updateExisting) {
|
||||||
return {
|
return {
|
||||||
ok: false,
|
ok: false,
|
||||||
warnings,
|
warnings,
|
||||||
@@ -824,6 +832,7 @@ export async function importSingleFurni(params: {
|
|||||||
|
|
||||||
// ── Create catalog entry (with duplicate check + category sub-page) ──
|
// ── Create catalog entry (with duplicate check + category sub-page) ──
|
||||||
let catalogItemId: number | null = null;
|
let catalogItemId: number | null = null;
|
||||||
|
let catalogUpdated = false;
|
||||||
try {
|
try {
|
||||||
const itemIdStr = String(spriteId);
|
const itemIdStr = String(spriteId);
|
||||||
|
|
||||||
@@ -834,9 +843,28 @@ export async function importSingleFurni(params: {
|
|||||||
|
|
||||||
if (existingCatalog.length > 0) {
|
if (existingCatalog.length > 0) {
|
||||||
catalogItemId = existingCatalog[0].id;
|
catalogItemId = existingCatalog[0].id;
|
||||||
warnings.push(
|
if (updateExisting) {
|
||||||
`Item already in catalog (catalog_item #${catalogItemId}, page ${existingCatalog[0].page_id}) — skipped duplicate`,
|
// 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 {
|
} else {
|
||||||
// Get or create the right category sub-page based on classname
|
// Get or create the right category sub-page based on classname
|
||||||
const categoryPageId = await getOrCreateCategoryPage(classname, itemType);
|
const categoryPageId = await getOrCreateCategoryPage(classname, itemType);
|
||||||
@@ -861,6 +889,7 @@ export async function importSingleFurni(params: {
|
|||||||
ok: true,
|
ok: true,
|
||||||
itemId: spriteId,
|
itemId: spriteId,
|
||||||
catalogItemId,
|
catalogItemId,
|
||||||
|
catalogUpdated,
|
||||||
dimensions: dims,
|
dimensions: dims,
|
||||||
spriteCount: conversionResult?.spriteCount,
|
spriteCount: conversionResult?.spriteCount,
|
||||||
warnings,
|
warnings,
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export interface ImportSingleResult {
|
|||||||
ok: boolean;
|
ok: boolean;
|
||||||
itemId?: number;
|
itemId?: number;
|
||||||
catalogItemId?: number | null;
|
catalogItemId?: number | null;
|
||||||
|
catalogUpdated?: boolean;
|
||||||
dimensions?: { x: number; y: number; z: number };
|
dimensions?: { x: number; y: number; z: number };
|
||||||
spriteCount?: number;
|
spriteCount?: number;
|
||||||
warnings: string[];
|
warnings: string[];
|
||||||
|
|||||||
Reference in new issue
Block a user