diff --git a/api/setup/saveWizard.cfm b/api/setup/saveWizard.cfm index f5ea127..70be0f7 100644 --- a/api/setup/saveWizard.cfm +++ b/api/setup/saveWizard.cfm @@ -23,6 +23,118 @@ */ response = { "OK": false, "steps": [], "errors": [] }; +itemsDir = expandPath("/uploads/items"); + +// Helper function: Resize image maintaining aspect ratio, fitting within maxSize box +function resizeToFit(img, maxSize) { + w = imageGetWidth(img); + h = imageGetHeight(img); + if (w <= maxSize && h <= maxSize) return img; + + if (w > h) { + newW = maxSize; + newH = int(h * (maxSize / w)); + } else { + newH = maxSize; + newW = int(w * (maxSize / h)); + } + imageResize(img, newW, newH, "highQuality"); + return img; +} + +// Helper function: Create square thumbnail (center crop) +function createSquareThumb(img, size) { + thumb = imageCopy(img, 0, 0, imageGetWidth(img), imageGetHeight(img)); + w = imageGetWidth(thumb); + h = imageGetHeight(thumb); + + // Resize so smallest dimension equals size + if (w > h) { + imageResize(thumb, "", size, "highQuality"); + } else { + imageResize(thumb, size, "", "highQuality"); + } + + // Center crop to square + w = imageGetWidth(thumb); + h = imageGetHeight(thumb); + if (w > h) { + x = int((w - h) / 2); + imageCrop(thumb, x, 0, h, h); + } else if (h > w) { + y = int((h - w) / 2); + imageCrop(thumb, 0, y, w, w); + } + + // Final resize to exact size + imageResize(thumb, size, size, "highQuality"); + return thumb; +} + +// Helper function: Download and save item image from URL +function downloadItemImage(itemID, imageUrl) { + try { + // Skip empty or invalid URLs + if (!len(trim(imageUrl))) return false; + + // Make URL absolute if relative + if (left(imageUrl, 2) == "//") { + imageUrl = "https:" & imageUrl; + } else if (left(imageUrl, 1) == "/") { + // Can't resolve relative URL without base - skip + return false; + } + + // Download the image + http url="#imageUrl#" method="GET" timeout="30" result="httpResult" { + httpparam type="header" name="User-Agent" value="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"; + } + + if (httpResult.statusCode != "200 OK" && !httpResult.statusCode.startsWith("200")) { + return false; + } + + // Check if it's actually an image + contentType = structKeyExists(httpResult.responseHeader, "Content-Type") ? httpResult.responseHeader["Content-Type"] : ""; + if (!findNoCase("image", contentType)) { + return false; + } + + // Write to temp file + tempFile = itemsDir & "/temp_" & itemID & "_" & createUUID() & ".tmp"; + fileWrite(tempFile, httpResult.fileContent); + + // Read as image + img = imageNew(tempFile); + + // Create thumbnail (128x128 square for retina) + thumb = createSquareThumb(img, 128); + thumbPath = itemsDir & "/" & itemID & "_thumb.jpg"; + imageWrite(thumb, thumbPath, 0.85); + + // Create medium size (400px max) + medium = imageCopy(img, 0, 0, imageGetWidth(img), imageGetHeight(img)); + medium = resizeToFit(medium, 400); + mediumPath = itemsDir & "/" & itemID & "_medium.jpg"; + imageWrite(medium, mediumPath, 0.85); + + // Save full size (max 1200px) + img = resizeToFit(img, 1200); + fullPath = itemsDir & "/" & itemID & ".jpg"; + imageWrite(img, fullPath, 0.90); + + // Clean up temp file + try { fileDelete(tempFile); } catch (any e) {} + + return true; + } catch (any e) { + // Clean up temp file if it exists + if (isDefined("tempFile") && fileExists(tempFile)) { + try { fileDelete(tempFile); } catch (any e2) {} + } + return false; + } +} try { requestBody = toString(getHttpRequestData().content); @@ -465,6 +577,7 @@ try { totalItems = 0; totalLinks = 0; + totalImages = 0; // Track item order within each category categoryItemOrder = {}; @@ -595,9 +708,20 @@ try { modOrder++; } } + + // Download item image if URL provided + itemImageUrl = ""; + if (structKeyExists(item, "imageUrl") && isSimpleValue(item.imageUrl)) { + itemImageUrl = trim(item.imageUrl); + } + if (len(itemImageUrl)) { + if (downloadItemImage(menuItemID, itemImageUrl)) { + totalImages++; + } + } } - response.steps.append("Created/updated " & totalItems & " items with " & totalLinks & " modifier links"); + response.steps.append("Created/updated " & totalItems & " items with " & totalLinks & " modifier links" & (totalImages > 0 ? " and " & totalImages & " images downloaded" : "")); response.OK = true; response.summary = { @@ -605,7 +729,8 @@ try { "categoriesProcessed": arrayLen(categories), "templatesProcessed": arrayLen(modTemplates), "itemsProcessed": totalItems, - "linksCreated": totalLinks + "linksCreated": totalLinks, + "imagesDownloaded": totalImages }; } catch (any e) {