← back to Designer Wallcoverings

mailers/cc-api/sync-china-seas.js

100 lines

'use strict';
/**
 * sync-china-seas.js — re-PUT the updated mailer HTML onto the existing
 * China Seas DRAFT activity, PRESERVING from/subject/reply/address AND the
 * attached contact_list_ids (PUT is full-replace — dropping the list wipes it).
 *
 * Phase 1 (default, read-only): discover the China Seas campaign + primary
 *   activity, GET its current state, print what WOULD change. No write.
 * Phase 2 (--confirm + CC_LIVE=1): PUT the new HTML, re-including the
 *   activity's existing contact_list_ids. NOT a send — draft content only.
 */
const fs = require('fs');
const path = require('path');
try { require('dotenv').config({ path: path.join(__dirname, '.env') }); } catch {}

const cc = require('./cc-client.js');
const HTML_PATH = path.join(__dirname, '..', 'china-seas-launch.html');
const CONFIRM = process.argv.includes('--confirm');

// minimal authed fetch reusing the client's token (CC_LIVE gate enforced there)
async function authed(method, urlPath, body) {
  const token = await cc.getAccessToken();
  const url = urlPath.startsWith('http') ? urlPath : `https://api.cc.email/v3${urlPath}`;
  const res = await fetch(url, {
    method,
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: 'application/json',
      ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
    },
    ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
  });
  const txt = await res.text();
  let j; try { j = txt ? JSON.parse(txt) : {}; } catch { j = { raw: txt }; }
  if (!res.ok) throw new Error(`${method} ${url} → ${res.status}: ${txt}`);
  return j;
}

(async () => {
  if (process.env.CC_LIVE !== '1') {
    console.log('CC_LIVE!=1 — read calls NO-OP. Set CC_LIVE=1 to run live.');
    return;
  }
  const html = fs.readFileSync(HTML_PATH, 'utf8');
  console.log(`loaded HTML: ${html.length} bytes`);

  // 1) find the China Seas campaign
  const camps = await authed('GET', '/emails?limit=50');
  const list = camps.campaigns || [];
  const cs = list.find(c => /china seas/i.test(c.name || ''));
  if (!cs) { console.log('No China Seas campaign found. Campaigns:', list.map(c => c.name)); return; }
  console.log(`campaign: "${cs.name}"  id=${cs.campaign_id}  status=${cs.current_status}`);

  // 2) find the primary_email activity id
  const detail = await authed('GET', `/emails/${cs.campaign_id}`);
  const acts = detail.campaign_activities || [];
  const primary = acts.find(a => a.role === 'primary_email') || acts[0];
  if (!primary) { console.log('No activity found on campaign.'); return; }
  const activityId = primary.campaign_activity_id;
  console.log(`primary activity id=${activityId}`);

  // 3) GET current activity state (with html so we can diff size) + list attachment
  const cur = await authed('GET', `/emails/activities/${activityId}?include=html_content,physical_address_in_footer`);
  const curLists = cur.contact_list_ids || [];
  console.log(`current: subject="${cur.subject}"  from=${cur.from_email}  lists=[${curLists.join(', ')}]  html=${(cur.html_content||'').length}b`);

  if (!curLists.length) {
    console.log('⚠️  WARNING: activity currently has NO contact_list_ids attached.');
  }

  // 4) build the full-replace payload — preserve everything, swap html only,
  //    and RE-INCLUDE contact_list_ids so the PUT doesn't wipe the list.
  const payload = {
    format_type: 5,
    from_name: cur.from_name,
    from_email: cur.from_email,
    reply_to_email: cur.reply_to_email,
    subject: cur.subject,
    ...(cur.preheader ? { preheader: cur.preheader } : {}),
    html_content: html,
    physical_address_in_footer: cur.physical_address_in_footer,
    ...(curLists.length ? { contact_list_ids: curLists } : {}),
  };

  if (!CONFIRM) {
    console.log('\n[DRY-RUN] Would PUT updated HTML to activity', activityId);
    console.log('  preserving from/subject/reply/address; re-including lists:', curLists);
    console.log('  new html bytes:', html.length);
    console.log('Run again with --confirm to push (CC_LIVE=1 already set).');
    return;
  }

  console.log('\nPUT (live) updated HTML →', activityId);
  const resp = await authed('PUT', `/emails/activities/${activityId}`, payload);
  // verify
  const after = await authed('GET', `/emails/activities/${activityId}?include=html_content`);
  console.log('✅ updated. after: html=%db  lists=[%s]',
    (after.html_content||'').length, (after.contact_list_ids||[]).join(', '));
})().catch(e => { console.error('ERR', e.message); process.exit(1); });