← back to Groundworks Activation
scripts/fix-images.js
54 lines
#!/usr/bin/env node
// Remediate the 9 image-FAILED products: try resized re-upload; if still failing, draft + Needs-Image tag.
const { Client } = require('pg');
const fs = require('fs');
const { execSync } = require('child_process');
const os = require('os');
const DOMAIN='designer-laboratory-sandbox.myshopify.com', API='2024-10';
const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').split('\n').find(l=>l.startsWith('SHOPIFY_ADMIN_TOKEN='))||'').split('=').slice(1).join('=').trim();
const GQL=`https://${DOMAIN}/admin/api/${API}/graphql.json`;
const REST=`https://${DOMAIN}/admin/api/${API}`;
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
async function gql(q,v){const r=await fetch(GQL,{method:'POST',headers:{'Content-Type':'application/json','X-Shopify-Access-Token':TOKEN},body:JSON.stringify({query:q,variables:v})});return (await r.json()).data;}
(async()=>{
const pg=new Client({host:'/tmp',database:'dw_unified'});await pg.connect();
const failed=JSON.parse(fs.readFileSync(__dirname+'/../data/verify-results.json')).fails.filter(f=>f.issues&&f.issues.includes('image'));
const out=[];
for(const f of failed){
const pid=f.pid;
const row=(await pg.query(`SELECT mfr_sku,image_url,name FROM groundworks_catalog WHERE dw_sku=$1`,[f.dw])).rows[0];
// download + resize with sips to <=2000px, re-upload via staged? Simpler: use REST product image with a resized data URL is not allowed.
// Resize locally then upload via REST images.json with attachment (base64).
let attached=false;
try{
const tmp=`${os.tmpdir()}/gw_${f.dw}.jpg`;
execSync(`curl -sL -A "Mozilla/5.0" -e "https://www.kravet.com/" "${row.image_url}" -o "${tmp}"`,{stdio:'ignore'});
// resize longest side to 2000, quality via sips
execSync(`sips -Z 2000 "${tmp}" --out "${tmp}" >/dev/null 2>&1`);
const b64=fs.readFileSync(tmp).toString('base64');
const r=await fetch(`${REST}/products/${pid}/images.json`,{method:'POST',headers:{'Content-Type':'application/json','X-Shopify-Access-Token':TOKEN},body:JSON.stringify({image:{attachment:b64,filename:`${row.mfr_sku}.jpg`}})});
const jr=await r.json();
if(jr.image&&jr.image.id) attached=true;
fs.unlinkSync(tmp);
}catch(e){out.push({dw:f.dw,resize_err:String(e).slice(0,120)});}
await sleep(1500);
// verify featuredImage now present
const d=await gql(`query($id:ID!){product(id:$id){featuredImage{url}}}`,{id:`gid://shopify/Product/${pid}`});
if(d.product.featuredImage){
// ensure ACTIVE (it already is) and record fixed
out.push({dw:f.dw,fixed:true});
console.log(` ✓ image fixed ${f.dw}`);
}else{
// draft + Needs-Image
await gql(`mutation($input:ProductInput!){productUpdate(input:$input){userErrors{message}}}`,{input:{id:`gid://shopify/Product/${pid}`,status:'DRAFT',tags:['Wallcovering','Groundworks','Needs-Image']}});
out.push({dw:f.dw,drafted:true});
console.log(` ⚠ drafted + Needs-Image ${f.dw}`);
}
await sleep(600);
}
await pg.end();
fs.writeFileSync(__dirname+'/../data/fix-images-results.json',JSON.stringify(out,null,2));
console.log('fixed=',out.filter(o=>o.fixed).length,'drafted=',out.filter(o=>o.drafted).length);
})();