← 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);
})();