-
-
Save devluis/60d0ef940a9b42323e23 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function getSignature() { | |
//pretty basic function for testing | |
if ( startupChecks()) { return; } | |
var email = SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue().toString(); | |
if ( email == "" ) { | |
Browser.msgBox("No email selected", "Please select a cell containing a user's email" , Browser.Buttons.OK); | |
return; | |
} | |
var result = authorisedUrlFetch(email, {}); | |
Browser.msgBox(result.getContentText()); | |
} | |
function setIndividualSignature() { | |
if ( startupChecks()) { return; } | |
var userData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Summary'); | |
var template = getTemplate(); | |
var row = SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getRow(); | |
if (userData.getRange(row, 1).isBlank() === true) { | |
var msg = "Please select a cell on a row containing the user who's signature you wish to update"; | |
Browser.msgBox('No user selected', msg, Browser.Buttons.OK); | |
} else { | |
setSignature(template, userData, row); | |
} | |
} | |
function setAllSignatures() { | |
if ( startupChecks()) { return; } | |
var userData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Summary'); | |
var template = getTemplate(); | |
//Go through each user listing | |
for ( row = 2; (userData.getRange(row, 1).isBlank() === false); row++) { | |
setSignature(template, userData, row); | |
} | |
} | |
function getTemplate(){ | |
var settings = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Signature Settings'); | |
var template = settings.getRange(2, 1).getValue().toString(); | |
//Substitute the company wide variables into the template | |
template = substituteVariablesFromRow(template, settings, 2); | |
return template; | |
} | |
function setSignature(template, userData, row){ | |
var groupData = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Signature Group Settings'); | |
//Google Apps Scripts always deals in ranges even if you just want one cell | |
//getValue returns an object, so convert it to a string | |
var email = userData.getRange(row, 1).getValue().toString(); | |
//Substitute in group variables, e.g those for groups of users | |
//this must be done before filling out user specific data as it was added after initial design | |
var signature = substituteGroupVariables(template, userData, groupData, row); | |
//Fill out the template with the data from the user's row to form the signatures | |
signature = substituteVariablesFromRow(signature, userData, row); | |
//The API docs say there is a 10,000 character limit | |
//https://developers.google.com/google-apps/email-settings/#updating_a_signature | |
if (signature.length > 10000) { Browser.msgBox('signature over 10000 characters for:' + email); } | |
sendSignature(email, signature); | |
} | |
function substituteVariablesFromRow(text, sheet, row) { | |
for ( col = 1; sheet.getRange(1, col).isBlank() === false; col++) { | |
var tag = sheet.getRange(1, col).getValue().toString(); | |
var value = sheet.getRange(row, col).getValue().toString(); | |
text = tagReplace(tag,value,text); | |
} | |
return text; | |
} | |
function substituteGroupVariables(text, dataSheet, lookupSheet, row) { | |
//this function isn't great but for now it will have to do | |
//iterate over the column names in the datasheet (e.g Primary Office, Certificates) | |
for ( dataCol = 1; dataSheet.getRange(1, dataCol).isBlank() === false; dataCol++) { | |
//the tag is the column heading as that is what will appear in the template (e.g "{Primary Office}") | |
var tag = dataSheet.getRange(1, dataCol).getValue().toString() ; | |
//iterate over the rows in the group settings sheet to find if a column has a set of values to lookup | |
for ( lookupRow = 1; lookupSheet.getRange(lookupRow, 1).isBlank() === false; lookupRow += 3) { | |
if ( tag === lookupSheet.getRange(lookupRow, 1).getValue().toString() ) { | |
var propertyValue = dataSheet.getRange(row, dataCol).getValue().toString(); | |
//iterate over the possible settings (e.g London, Edinburg, Madrid) | |
for ( lookupCol = 2; lookupSheet.getRange(lookupRow, lookupCol).isBlank() === false; lookupCol++) { | |
//search for substring matches as this allows for lists (e.g a list of certifications) | |
if ( lookupSheet.getRange(lookupRow, lookupCol).getValue().toString().indexOf(propertyValue) !== -1 ) { | |
var value = lookupSheet.getRange(lookupRow+1, lookupCol).getValue().toString(); | |
text = tagReplace(tag, value, text); | |
} | |
} | |
} | |
} | |
} | |
return text; | |
} | |
function tagReplace(tag, value, text){ | |
var escapeChar = ScriptProperties.getProperty('escapeChar'); | |
var unEscapeChar = ScriptProperties.getProperty('unEscapeChar'); | |
tag = escapeChar + tag + unEscapeChar; | |
//could be done as a regex to avoid this loop but then I'd have two problems | |
while (text.indexOf(tag) !== -1) { | |
text = text.replace(tag, value); | |
} | |
return text; | |
} | |
function sendSignature(email, signature) { | |
// https://developers.google.com/google-apps/email-settings/#updating_a_signature | |
var requestData = { | |
'method': 'PUT', | |
'contentType': 'application/atom+xml', | |
'payload': getPayload(signature) | |
}; | |
var result = authorisedUrlFetch(email, requestData); | |
if (result.getResponseCode() != 200) { | |
var msg = 'There was an error sending ' + email + "'s signature to Google"; | |
Browser.msgBox('Error settings signature', msg, Browser.Buttons.OK); | |
} | |
} | |
function getPayload(signature) { | |
//First line is needed for XML, second isn't but we might as well do it for consistency | |
signature = signature.replace(/&/g, '&').replace(/</g, '<'); | |
signature = signature.replace(/>/g, '>').replace(/'/g, ''').replace(/"/g, '"'); | |
//Unfortunately when inside app script document.createElement doesn't work so lets just hardcode the XML for now | |
var xml = '<?xml version="1.0" encoding="utf-8"?>' + | |
'<atom:entry xmlns:atom="http://www.w3.org/2005/Atom" xmlns:apps="http://schemas.google.com/apps/2006" >' + | |
'<apps:property name="signature" value="'+signature+'" /></atom:entry>'; | |
return xml; | |
} | |
function authorisedUrlFetch(email, requestData) { | |
//takes request data and wraps oauth authentication around it before sending out the request | |
// https://developers.google.com/apps-script/class_oauthconfig | |
// http://support.google.com/a/bin/answer.py?hl=en&hlrm=en&answer=162105 | |
// https://developers.google.com/apps-script/articles/picasa_google_apis#section2a | |
// The scope from https://developers.google.com/google-apps/email-settings/ has to be URIcomponent encoded | |
var oAuthConfig = UrlFetchApp.addOAuthService('google'); | |
oAuthConfig.setConsumerSecret(ScriptProperties.getProperty('oAuthConsumerSecret')); | |
oAuthConfig.setConsumerKey(ScriptProperties.getProperty('oAuthClientID')); | |
oAuthConfig.setRequestTokenUrl('https://www.google.com/accounts/OAuthGetRequestToken?scope=https%3A%2F%2Fapps-apis.google.com%2Fa%2Ffeeds%2Femailsettings%2F'); | |
oAuthConfig.setAuthorizationUrl('https://www.google.com/accounts/OAuthAuthorizeToken'); | |
oAuthConfig.setAccessTokenUrl('https://www.google.com/accounts/OAuthGetAccessToken'); | |
UrlFetchApp.addOAuthService(oAuthConfig); | |
requestData['oAuthServiceName'] = 'google'; | |
requestData['oAuthUseToken'] = 'always'; | |
var emailParts = email.split('@'); | |
var url = 'https://apps-apis.google.com/a/feeds/emailsettings/2.0/' + emailParts[1] + '/' + emailParts[0] + '/signature'; | |
var result = UrlFetchApp.fetch(url, requestData); | |
if ( result.getResponseCode() != 200 ) { | |
//Do some logging if something goes wrong | |
//Too deep to give the user a meaningful error though so pass the result back up anyway | |
Logger.log('Error on fetch on' + url); | |
Logger.log(requestData); | |
Logger.log(result.getResponseCode()); | |
Logger.log(result.getHeaders()); | |
Logger.log(result.getContentText()); | |
} | |
return result; | |
} | |
function onOpen() { | |
//add a toolbar and list the functions you want to call externally | |
var ss = SpreadsheetApp.getActiveSpreadsheet(); | |
var menuEntries = []; | |
menuEntries.push({name: 'Set All Signatures', functionName: 'setAllSignatures'}); | |
menuEntries.push({name: 'Set Individual Signature', functionName: 'setIndividualSignature'}); | |
menuEntries.push({name: 'Get Signature', functionName: 'getSignature'}); | |
ss.addMenu('Signatures', menuEntries); | |
startupChecks(); | |
} | |
function startupChecks() { | |
//Check that everything that is needed to run is there | |
//I don't check that any of it makes sense, just that it exists. | |
var requiredProperties = []; | |
//the help text looks pretty terrible but it is better than nothing | |
var oAuthHelp = 'Goto https://code.google.com/apis/console#:access and register as an "Installed application" \n'+ | |
'Then add the ClientID to authorised 3rd party clients \n'+ | |
'With scope https://apps-apis.google.com/a/feeds/emailsettings/ \n'+ | |
'The script may then need authorising, this can be done by running one of the scripts from the script editor'; | |
requiredProperties.push({name: 'oAuthClientID', help: oAuthHelp}); | |
requiredProperties.push({name: 'oAuthConsumerSecret', help: oAuthHelp}); | |
requiredProperties.push({name: 'escapeChar', help: 'A character or sequence to go before variables that will be substituted, e.g { ` ${'}); | |
requiredProperties.push({name: 'unEscapeChar', help: 'A character or sequence to go after variables that will be substituted, e.g } ` }$'}); | |
var requiredSheets = []; | |
requiredSheets.push({name: 'Summary', help: 'A "Summary" sheet must exist that contains a 1 header row and 1 row per user, with no gaps in either the 1st column or row, the 1st row must be the users usernames'}); | |
requiredSheets.push({name: 'Signature Settings', help: 'A "Signature Settings" sheet must exist that contains a the template in cell 2A and then has 1 header row and 1 row per company wide variable, with no empty header cells'}); | |
requiredSheets.push({name: 'Signature Group Settings', help: 'A "Signature Group Settings" sheet must exist that contains 3 Rows (setting values, what to substitute, comments) with every third row containing a column header'}); | |
var fail = false; | |
for ( i = 0; i < requiredProperties.length; i++) { | |
var property = ScriptProperties.getProperty(requiredProperties[i].name); | |
if (property == null) { | |
var title = 'Script Property ' + requiredProperties[i].name + ' is required'; | |
var prompt = requiredProperties[i].help; | |
var newValue = Browser.inputBox(title, prompt, Browser.Buttons.OK_CANCEL); | |
if ((newValue === '') || (newValue === 'cancel')) { | |
fail = true; | |
} else { | |
ScriptProperties.setProperty(requiredProperties[i].name, newValue); | |
} | |
} | |
} | |
for ( i = 0; i < requiredSheets.length; i++) { | |
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(requiredSheets[i].name); | |
if (sheet == null) { | |
fail = true; | |
var title = 'Sheet ' + requiredSheets[i].name + ' is required'; | |
var prompt = requiredSheets[i].help; | |
Browser.msgBox(title, prompt, Browser.Buttons.OK); | |
} | |
} | |
return fail; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment