2016-06-17 21:05:46 -07:00
// Copy ZenProspect contacts with email replies into Close.io leads
'use strict' ;
if ( process . argv . length !== 4 ) {
console . log ( "Usage: node <script> <Close.io general API key> <ZenProspect auth token>" ) ;
process . exit ( ) ;
}
const closeIoApiKey = process . argv [ 2 ] ;
const zpAuthToken = process . argv [ 3 ] ;
const scriptStartTime = new Date ( ) ;
const async = require ( 'async' ) ;
const request = require ( 'request' ) ;
const zpPageSize = 100 ;
getZPRepliedContacts ( ( err , emailContactMap ) => {
if ( err ) {
console . log ( err ) ;
return ;
}
const tasks = [ ] ;
for ( const email in emailContactMap ) {
const contact = emailContactMap [ email ] ;
// if (contact.organization !== 'Cabarrus County Schools') continue;
tasks . push ( createUpsertCloseLeadFn ( contact ) ) ;
}
async . parallel ( tasks , ( err , results ) => {
if ( err ) console . log ( err ) ;
2016-06-18 23:21:06 -07:00
log ( "Script runtime: " + ( new Date ( ) - scriptStartTime ) ) ;
2016-06-17 21:05:46 -07:00
} ) ;
} ) ;
function createCloseLead ( zpContact , done ) {
const postData = {
name : zpContact . organization ,
status : 'Contacted' ,
contacts : [
{
name : zpContact . name ,
title : zpContact . title ,
emails : [ { email : zpContact . email } ]
}
] ,
custom : {
lastUpdated : new Date ( ) ,
'Lead Origin' : 'outbound campaign'
}
} ;
if ( zpContact . phone ) {
postData . contacts [ 0 ] . phones = [ { phone : zpContact . phone } ] ;
}
const options = {
uri : ` https:// ${ closeIoApiKey } :X@app.close.io/api/v1/lead/ ` ,
body : JSON . stringify ( postData )
} ;
request . post ( options , ( error , response , body ) => {
if ( error ) return done ( error ) ;
const newLead = JSON . parse ( body ) ;
if ( newLead . errors || newLead [ 'field-errors' ] ) {
console . error ( ` New lead POST error for ${ zpContact . name } ${ zpContact . organization } ` ) ;
return done ( newLead . errors || newLead [ 'field-errors' ] ) ;
}
return done ( ) ;
} ) ;
}
function updateCloseLead ( zpContact , existingLead , done ) {
const putData = {
status : 'Contacted' ,
'custom.lastUpdated' : new Date ( ) ,
'custom.Lead Origin' : 'outbound campaign'
} ;
const options = {
uri : ` https:// ${ closeIoApiKey } :X@app.close.io/api/v1/lead/ ${ existingLead . id } / ` ,
body : JSON . stringify ( putData )
} ;
request . put ( options , ( error , response , body ) => {
if ( error ) return done ( error ) ;
const result = JSON . parse ( body ) ;
if ( result . errors || result [ 'field-errors' ] ) {
return done ( ` Update existing lead PUT error for ${ existingLead . id } ${ zpContact . email } ${ result . errors || result [ 'field-errors' ] } ` ) ;
}
const postData = {
lead _id : existingLead . id ,
name : zpContact . name ,
title : zpContact . title ,
emails : [ { email : zpContact . email } ]
} ;
const options = {
uri : ` https:// ${ closeIoApiKey } :X@app.close.io/api/v1/contact/ ` ,
body : JSON . stringify ( postData )
} ;
request . post ( options , ( error , response , body ) => {
if ( error ) return done ( error ) ;
const result = JSON . parse ( body ) ;
if ( result . errors || result [ 'field-errors' ] ) {
return done ( ` New Contact POST error for ${ existingLead . id } ${ zpContact . email } ${ result . errors || result [ 'field-errors' ] } ` ) ;
}
return done ( ) ;
} ) ;
} ) ;
}
function createUpsertCloseLeadFn ( zpContact ) {
return ( done ) => {
// console.log(`DEBUG: createUpsertCloseLeadFn ${zpContact.organization} ${zpContact.email}`);
const query = ` email: ${ zpContact . email } ` ;
const url = ` https:// ${ closeIoApiKey } :X@app.close.io/api/v1/lead/?query= ${ encodeURIComponent ( query ) } ` ;
request . get ( url , ( error , response , body ) => {
if ( error ) return done ( error ) ;
const data = JSON . parse ( body ) ;
if ( data . total _results != 0 ) return done ( ) ;
const query = ` name: ${ zpContact . organization } ` ;
const url = ` https:// ${ closeIoApiKey } :X@app.close.io/api/v1/lead/?query= ${ encodeURIComponent ( query ) } ` ;
request . get ( url , ( error , response , body ) => {
if ( error ) return done ( error ) ;
const data = JSON . parse ( body ) ;
if ( data . total _results === 0 ) {
console . log ( ` DEBUG: Creating lead for ${ zpContact . organization } ${ zpContact . email } ` ) ;
return createCloseLead ( zpContact , done ) ;
}
else {
const existingLead = data . data [ 0 ] ;
console . log ( ` DEBUG: Adding ${ zpContact . organization } ${ zpContact . email } to ${ existingLead . id } ` ) ;
return updateCloseLead ( zpContact , existingLead , done ) ;
}
} ) ;
} ) ;
} ;
}
function getZPRepliedContactsPage ( contacts , page , done ) {
// console.log(`DEBUG: Fetching page ${page} ${zpPageSize}...`);
const options = {
url : ` https://www.zenprospect.com/api/v1/contacts/search?codecombat_special_auth_token= ${ zpAuthToken } &page= ${ page } &per_page= ${ zpPageSize } ` ,
headers : {
'Accept' : 'application/json'
}
} ;
request . get ( options , ( err , response , body ) => {
if ( err ) return done ( err ) ;
const data = JSON . parse ( body ) ;
for ( let contact of data . contacts ) {
if ( contact . email _replied ) {
contacts . push ( {
organization : contact . organization _name ,
name : contact . name ,
title : contact . title ,
email : contact . email ,
phone : contact . phone ,
data : contact
} ) ;
}
}
return done ( null , data . pipeline _total ) ;
} ) ;
}
function getZPRepliedContacts ( done ) {
// Get first page to get total contact count for parallized page fetches
const contacts = [ ] ;
getZPRepliedContactsPage ( contacts , 0 , ( err , total ) => {
if ( err ) return done ( err ) ;
const createGetZPLeadsPage = ( leads , page ) => {
return ( done ) => {
getZPRepliedContactsPage ( leads , page , done ) ;
} ;
}
const tasks = [ ] ;
for ( let i = 1 ; ( i - 1 ) * zpPageSize < total ; i ++ ) {
tasks . push ( createGetZPLeadsPage ( contacts , i ) ) ;
}
async . parallel ( tasks , ( err , results ) => {
if ( err ) return done ( err ) ;
const emailContactMap = { } ;
for ( const contact of contacts ) {
if ( ! contact . organization || ! contact . name || ! contact . title || ! contact . email ) {
console . log ( JSON . stringify ( contact , null , 2 ) ) ;
return done ( ` DEBUG: missing data for zp contact: ` ) ;
}
if ( ! emailContactMap [ contact . email ] ) emailContactMap [ contact . email ] = contact ;
}
2016-06-18 23:21:06 -07:00
log ( ` ${ total } total ZP contacts, ${ Object . keys ( emailContactMap ) . length } with replies ` ) ;
2016-06-17 21:05:46 -07:00
return done ( null , emailContactMap ) ;
} ) ;
} ) ;
}
2016-06-18 23:21:06 -07:00
function log ( str ) {
console . log ( new Date ( ) . toISOString ( ) + " " + str ) ;
}