Try it out
Apps
Blog
About
Contact
Developers
Docs
Login
Developers
salesforce@obindo.com
Written by
Chuck
Search for any contacts in a message and save them directly to Salesforce.com.
/************************* Documentation: API Reference: https://www.salesforce.com/us/developer/docs/api/index_Left.htm **************************/ //#region PRIVATE consumer key and secret var authorizeUrl= "https://login.salesforce.com/services/oauth2/authorize?"; var tokenUrl= "https://login.salesforce.com/services/oauth2/token?"; var newObjectUrl= "/services/data/v28.0/sobjects/"; var queryUrl= "/services/data/v28.0/query/"; var maxDescriptionLength= 7500; var maxSubjectLength= 255; var unknown= 'unknown'; oauth2.getAuthRedirectUrl= function(q) { if (q) tokens.requestToken= util.getObjectFromQueryArgs(q); var args= { response_type: "code", client_id: consumerKey, redirect_uri: oauth2.getCallbackUrl(true), state: tokens.getId() }; return authorizeUrl + util.getQueryArgsFromObject(args); } oauth2.onAuthResponse= function(q) { var authResponse= util.getObjectFromQueryArgs(q); var args= { grant_type: "authorization_code", client_id: consumerKey, client_secret: consumerSecret, redirect_uri: oauth2.getCallbackUrl(true), code: authResponse.code }; var accessResponse= post({ url: tokenUrl + util.getQueryArgsFromObject(args) }); tokens.loadFromId(authResponse.state); tokens.accessToken= util.jsonify(accessResponse.text); if (tokens.requestToken && tokens.requestToken.redirect_uri) return tokens.requestToken.redirect_uri; } oauth2.refreshAccessToken= function() { var rt= tokens.accessToken.refresh_token; var args= { grant_type: "refresh_token", refresh_token: rt, client_id: consumerKey, client_secret: consumerSecret }; var url= tokenUrl + util.getQueryArgsFromObject(args); var response= post({ url: url }); var newToken= util.jsonify(response.text); newToken.refresh_token= rt; tokens.accessToken= newToken; } //create("Account", {Name: "Soba Send"}); //create("Lead", { FirstName: "Another", LastName: "Possible", Company: "Nabisco" }); //create("Contact", { FirstName: "Chuck", LastName: "Kreuser" }); function create(objectName, o) { var url= tokens.accessToken.instance_url + newObjectUrl + objectName; var header= { Authorization : 'Bearer ' + tokens.accessToken.access_token, "X-PrettyPrint": "1", "Content-Type": "application/json" }; return post({ url: url, header: header, body: util.stringify(o) }); } function update(objectName, id, fields) { var url= tokens.accessToken.instance_url + newObjectUrl + objectName + '/' + id; var header= { Authorization : 'Bearer ' + tokens.accessToken.access_token, "X-PrettyPrint": "1", "Content-Type": "application/json" }; return patch({ url: url, header: header, body: util.stringify(fields) }); } //runQuery("SELECT name,id from Account where name='Obindo'"); //runQuery("SELECT name,id,firstName,lastName from Lead where LastName='McGinty'"); //runQuery("SELECT name,id,firstName,lastName,account.name from Contact where FirstName='Joe' and LastName='Kleinschmidt'"); function runQuery(q) { var url= tokens.accessToken.instance_url + queryUrl + "?q=" + util.urlEncode(q); var header= { Authorization : 'Bearer ' + tokens.accessToken.access_token, "X-PrettyPrint": "1" }; return get({ url: url, header: header }); } function getNames(name) { if (!name) return {}; var s= name.replace(/^\s+|\s+$/g,''); //trim s= s.replace(/\s{2,}/g,' '); //consecutive spaces if (s.length == 0) return {}; var arr= s.split(' '); if (arr.length == 0) return {}; if (arr.length == 1) return { first: arr[0] }; if (arr.length == 2) return { first: arr[0], last: arr[1] }; if (arr.length == 3 && isInitial(arr[1])) return { first: arr[0], last: arr[2] }; var i= s.lastIndexOf(' '); return { first: s.substring(0,i), last: s.substring(i+1) }; function isInitial(s) { if (s.length == 1) return true; return (s.length == 2 && s.substring(1) == '.') } } function getLeadFromQuery(q) { var response= runQuery(q); var j= util.jsonify(response.text); return (j.records && j.records.length > 0) ? j.records[0] : null; } function getLeadFromId(id) { var q= "SELECT name,id,firstName,lastName,email from "; q+= "Lead where Id='"+ id +"'"; return getLeadFromQuery(q); } function getLead(contact) { var q= "SELECT name,id,firstName,lastName,email from "; q+= "Lead where Email='"+ contact.emailAddress.toLowerCase().replace("'","\\'") +"'"; return getLeadFromQuery(q); } function createLead(contact, names) { var lead= { Email: contact.emailAddress.toLowerCase(), Company: getCompanyName(contact), FirstName: (names.first) ? names.first : unknown, LastName: (names.last) ? names.last : unknown }; var response= create('Lead', lead); return util.jsonify(response.text).id; } function getUpdates(lead, names) { var bUpdate= false; var fields= {}; if (lead.FirstName == unknown && names.first) { bUpdate= true; fields.FirstName= names.first; } if (lead.LastName == unknown && names.last) { bUpdate= true; fields.LastName= names.last; } return (bUpdate) ? fields : null; } function getContacts(message) { if (message.selections && message.selections.leads) //set in extension! return message.selections.leads; var contacts= []; if (message.to) for (var i=0; i < message.to.length; i++) if (message.to[i].emailAddress.toLowerCase().indexOf('@obindo.com') < 0) contacts.push(message.to[i]); if (contacts.length > 0) //To addresses exist return contacts; if (!message.messages || message.messages.length == 0) //no submessages return contacts; var from= message.messages[0].from; return (from && from.emailAddress) ? [ from ] : []; } function createTask(subject, text, leadId, files) { var task= { 'WhoID': leadId, 'Subject': subject, 'Description': text, 'Status': 'Completed' }; var response= create('Task', task); if (files.length == 0) return; var url= tokens.accessToken.instance_url + newObjectUrl + 'Attachment'; var header= { Authorization : 'Bearer ' + tokens.accessToken.access_token }; var id= util.jsonify(response.text).id; for (var i=0; i < files.length; i++) { var details= { Name: files[i].name, ParentId: id }; var args= { entity_document: util.stringify(details), Body: files[i] }; post({ url: url, header: header, args: args }); } } function sendConfirm(email, found, created, files) { var text= ''; var emailArgs= { to: email, templateFields: { recipientName: message.from.name } }; var bOne= ((found.length + created.length) == 1); if (found.length == 0 && created.length == 0) { var src= message.source; if (src && src.type && src.type == 'getstarted') //no empty message from other source return; emailArgs.subject= 'Obindo didn\'t know what to do with that one'; text= 'Sorry, we couldn\'t find any names on which to save lead activity. '; text+= 'We look in the To field or at the sender of a forwarded email.'; text+= '\n\nPlease try again the next time you\'d like to save lead activity to Salesforce.'; } else { emailArgs.subject= 'Obindo saved your lead activity to Salesforce!'; text= 'Obindo'; if (created.length > 0) text+= ' created ' + created.length + ' new lead' + ((created.length > 1) ? 's' : ''); if (found.length > 0 && created.length > 0) text+= ','; if (found.length > 0) text+= ' found ' + found.length + ' lead' + ((found.length > 1) ? 's' : ''); var total= created.length + found.length; text+= ' and saved the email in ' + ((total > 1) ? 'their' : 'his or her') + ' Activity History.'; for (var i=0; i < found.length; i++) text+= '\n\n' + getLeadDisplay(found[i]); for (var i=0; i < created.length; i++) text+= '\n\n' + getLeadDisplay(created[i]); if (files.length > 0) { text+= '\n\nWe also uploaded ' + files.length + ' attachment' text+= ((files.length > 1) ? 's' : '') + ' to ' + ((total > 1) ? 'each' : 'the') + ' email.'; for (var i=0; i < files.length; i++) text+= '\n' + files[i].name; } var linkLead= (created.length > 0) ? created[0] : found[0]; message.appUrl= tokens.accessToken.instance_url + '/' + linkLead.Id; emailArgs.templateFields.buttonText= 'View in Salesforce'; emailArgs.templateFields.buttonLink= message.appUrl; } text+= '\n\nThanks for using Obindo!'; emailArgs.text= text; sendEmail(emailArgs); function getLeadDisplay(lead) { var name= lead.Name; if (lead.FirstName == unknown && lead.LastName == unknown) name= lead.Email; else if (lead.LastName == unknown) name= lead.FirstName; return (bOne) ? name : name + '\n' + tokens.accessToken.instance_url + '/' + lead.Id; } } function truncate(text, length) { if (text.length < length) return text; var s= text.substring(0, length); var i= s.lastIndexOf(' '); return (i > 0) ? s.substring(0,i) : s; } function getSubject(message) { return (message.subject) ? truncate(message.subject, maxSubjectLength) : '(no subject)'; } function getDescription(message) { return truncate(message.fullText, maxDescriptionLength); } function getCompanyName(contact) { var email= contact.emailAddress; if (!email) return unknown; var i= email.indexOf('@'); if (i < 0 || i == email.length - 1) return unknown; var domains= [ 'gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com' ]; var domain= email.substring(i+1).toLowerCase(); for (var i=0; i < domains.length; i++) if (domain == domains[i]) return unknown; return domain; } function getUploadFiles(files) { var uploads= []; if (!files) return uploads; for (var i=0; i < files.length; i++) if (files[i].contentType.indexOf('image') < 0 || !files[i].embedId) { //no embedded images //files[i].name= files[i].name.replace(/;/g,','); //doesn't like semicolons uploads.push(files[i]); } return uploads; } $(function() { var contacts= getContacts(message); if (contacts.length == 0) { sendConfirm(message.from.emailAddress, [], []); return; } var description= getDescription(message); var subject= getSubject(message); var files= getUploadFiles(message.files); var found= []; var created= []; for (var i=0; i < contacts.length; i++) { var lead= getLead(contacts[i]); var names= getNames(contacts[i].name); if (!lead) { var id= createLead(contacts[i], names); lead= getLeadFromId(id); created.push(lead); } else { var updates= getUpdates(lead, names); if (updates) { update('Lead', lead.Id, updates); lead= getLeadFromId(lead.Id); } found.push(lead); } createTask(subject, description, lead.Id, files); } sendConfirm(message.from.emailAddress, found, created, files); });