|
|
@@ -1,8 +1,14 @@ |
|
|
//moved these outside to prevent multiple calls as they need be consitent for the duration of the scripts run anyway |
|
|
var regOpen = sanitize(UserProperties.getProperty('regOpen')); |
|
|
var tagOpen = sanitize(UserProperties.getProperty('tagOpen')); |
|
|
var regClose = sanitize(UserProperties.getProperty('regClose')); |
|
|
var tagClose = sanitize(UserProperties.getProperty('tagClose')); |
|
|
|
|
|
function getSignature() { |
|
|
//pretty basic function for testing |
|
|
if ( startupChecks()) { return; } |
|
|
var email = SpreadsheetApp.getActiveSpreadsheet().getActiveCell().getValue().toString(); |
|
|
if ( email == "" ) { |
|
|
if ( email === "" ) { |
|
|
Browser.msgBox("No email selected", "Please select a cell containing a user's email" , Browser.Buttons.OK); |
|
|
return; |
|
|
} |
|
|
@@ -11,32 +17,37 @@ function getSignature() { |
|
|
} |
|
|
|
|
|
function setIndividualSignature() { |
|
|
Logger.log('[%s]\t Starting setIndividualSignature run', Date()); |
|
|
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); |
|
|
Browser.msgBox('No valid user selected', msg, Browser.Buttons.OK); |
|
|
} else { |
|
|
setSignature(template, userData, row); |
|
|
} |
|
|
Logger.log('[%s]\t Completed setIndividualSignature run', Date()); |
|
|
} |
|
|
|
|
|
function setAllSignatures() { |
|
|
Logger.log('[%s]\t Starting setAllSignatures run', Date()); |
|
|
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++) { |
|
|
for ( row = 2; row <= userData.getLastRow() ; row++) { |
|
|
setSignature(template, userData, row); |
|
|
} |
|
|
Logger.log('[%s]\t Completed setAllSignatures run', Date()); |
|
|
} |
|
|
|
|
|
function getTemplate(){ |
|
|
Logger.log('[%s]\t Getting Template', Date()); |
|
|
var settings = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Signature Settings'); |
|
|
var template = settings.getRange(2, 1).getValue().toString(); |
|
|
|
|
|
@@ -51,70 +62,90 @@ function setSignature(template, userData, row){ |
|
|
|
|
|
//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(); |
|
|
var email = userData.getRange(row, 1).getValue().toString(); |
|
|
|
|
|
//quick exit if the user isn't in the domain |
|
|
if (!checkUserIsValid(email)){ |
|
|
Logger.log('[%s]\t Skipping user %s',Date(),email); |
|
|
return; |
|
|
} |
|
|
|
|
|
//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 |
|
|
Logger.log('[%s]\t Substituting Group Variables for user %s',Date(),email); |
|
|
var signature = substituteGroupVariables(template, userData, groupData, row); |
|
|
|
|
|
//Fill out the template with the data from the user's row to form the signatures |
|
|
Logger.log('[%s]\t Substituting Individual Variables for user %s',Date(),email); |
|
|
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); } |
|
|
|
|
|
Logger.log('[%s]\t Sending signature for user %s',Date(),email); |
|
|
sendSignature(email, signature); |
|
|
Logger.log('[%s]\t Processing complete for user %s',Date(),email); |
|
|
} |
|
|
|
|
|
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); |
|
|
function substituteVariablesFromRow(text, sheet, row) { |
|
|
//Generating two lists avoids the need to do lots of individual calls to the sheet |
|
|
var tags = sheet.getSheetValues(1, 1, 1, sheet.getLastColumn())[0]; |
|
|
var values = sheet.getSheetValues(row, 1, 1, sheet.getLastColumn())[0]; |
|
|
for ( v = 0; v < values.length; v++){ |
|
|
text = tagReplace(tags[v],values[v],text); |
|
|
} |
|
|
return text; |
|
|
} |
|
|
|
|
|
function substituteGroupVariables(text, dataSheet, lookupSheet, row) { |
|
|
//this function isn't great but for now it will have to do |
|
|
//this function is still not great but at least it makes use of getSheet |
|
|
var tags = dataSheet.getSheetValues(1, 1, 1, dataSheet.getLastColumn())[0]; |
|
|
var values = dataSheet.getSheetValues(row, 1, 1, dataSheet.getLastColumn())[0]; |
|
|
var GroupVariables = lookupSheet.getSheetValues(1, 1, lookupSheet.getLastRow(),1); |
|
|
|
|
|
//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() ; |
|
|
//for each GroupVariable |
|
|
for (j = 0; j < GroupVariables.length ; j += 3){ |
|
|
|
|
|
//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(); |
|
|
//find the column for later changing the value |
|
|
for (i = 0; i < tags.length; i++){ |
|
|
if (tags[i] === GroupVariables[j][0]){ |
|
|
|
|
|
//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); |
|
|
//and build a lookup table to switch it out |
|
|
var lookupTable = lookupSheet.getSheetValues(j+1,2,2,lookupSheet.getLastColumn()-1); |
|
|
for ( k=0;k<lookupTable[0].length;k++) { |
|
|
if (values[i] === lookupTable[0][k]){ |
|
|
text = tagReplace(tags[i], lookupTable[1][k], text); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
return text; |
|
|
} |
|
|
|
|
|
function sanitize(text){ |
|
|
var invalid = ["[","^","$",".","|","?","*","+","(",")"]; |
|
|
for(m=0;m<invalid.length;m++){ |
|
|
text = text.replace(invalid[m],"\\"+invalid[m]); |
|
|
} |
|
|
return text; |
|
|
} |
|
|
|
|
|
|
|
|
function tagReplace(tag, value, text){ |
|
|
var escapeChar = ScriptProperties.getProperty('escapeChar'); |
|
|
var unEscapeChar = ScriptProperties.getProperty('unEscapeChar'); |
|
|
var regex = new RegExp("(.*)"+regOpen+'(.*?)'+tagOpen+tag+tagClose+'(.*?)'+regClose+"(.*)","g"); |
|
|
value = value.toString().replace("$","\\$"); |
|
|
if ((value !== "")) { value = "$2"+value+"$3"; } |
|
|
value = "$1"+value+"$4"; |
|
|
|
|
|
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); |
|
|
//I'm sure this can be avoided by making the regex more complicated, but this will do for now |
|
|
for(q=0; ((text.match(regex)) && q<128); q++ ){ |
|
|
text = text.replace(regex,value); |
|
|
} |
|
|
|
|
|
return text; |
|
|
} |
|
|
|
|
|
@@ -132,6 +163,14 @@ function sendSignature(email, signature) { |
|
|
} |
|
|
} |
|
|
|
|
|
function checkUserIsValid(user){ |
|
|
var userList = UserManager.getAllUsers(); |
|
|
for ( u=0 ; u < userList.length ; u++ ) { |
|
|
if (userList[u].getEmail() === user){ return true; } |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
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, '<'); |
|
|
@@ -152,8 +191,8 @@ function authorisedUrlFetch(email, requestData) { |
|
|
// 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.setConsumerSecret(UserProperties.getProperty('oAuthConsumerSecret')); |
|
|
oAuthConfig.setConsumerKey(UserProperties.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'); |
|
|
@@ -185,7 +224,6 @@ function onOpen() { |
|
|
menuEntries.push({name: 'Set Individual Signature', functionName: 'setIndividualSignature'}); |
|
|
menuEntries.push({name: 'Get Signature', functionName: 'getSignature'}); |
|
|
ss.addMenu('Signatures', menuEntries); |
|
|
startupChecks(); |
|
|
} |
|
|
|
|
|
function startupChecks() { |
|
|
@@ -200,35 +238,37 @@ function startupChecks() { |
|
|
'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 } ` }$'}); |
|
|
requiredProperties.push({name: 'regOpen', help: 'A character or sequence to go before sections to be substituded, e.g ${'}); |
|
|
requiredProperties.push({name: 'regClose', help: 'A character or sequence to go after sections that will be substituted, e.g } or }$'}); |
|
|
requiredProperties.push({name: 'tagOpen', help: 'A character or sequence to go before tags to be substituded, e.g {'}); |
|
|
requiredProperties.push({name: 'tagClose', help: 'A character or sequence to go after tags that will be substituted, e.g } or }$'}); |
|
|
|
|
|
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); |
|
|
for ( s = 0; s < requiredProperties.length; s++) { |
|
|
var property = UserProperties.getProperty(requiredProperties[s].name); |
|
|
if (property == null) { |
|
|
var title = 'Script Property ' + requiredProperties[i].name + ' is required'; |
|
|
var prompt = requiredProperties[i].help; |
|
|
var title = 'Script Property ' + requiredProperties[s].name + ' is required'; |
|
|
var prompt = requiredProperties[s].help; |
|
|
var newValue = Browser.inputBox(title, prompt, Browser.Buttons.OK_CANCEL); |
|
|
if ((newValue === '') || (newValue === 'cancel')) { |
|
|
fail = true; |
|
|
} else { |
|
|
ScriptProperties.setProperty(requiredProperties[i].name, newValue); |
|
|
UserProperties.setProperty(requiredProperties[s].name, newValue); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
for ( i = 0; i < requiredSheets.length; i++) { |
|
|
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(requiredSheets[i].name); |
|
|
for ( s = 0; s < requiredSheets.length; s++) { |
|
|
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(requiredSheets[s].name); |
|
|
if (sheet == null) { |
|
|
fail = true; |
|
|
var title = 'Sheet ' + requiredSheets[i].name + ' is required'; |
|
|
var prompt = requiredSheets[i].help; |
|
|
var title = 'Sheet ' + requiredSheets[s].name + ' is required'; |
|
|
var prompt = requiredSheets[s].help; |
|
|
Browser.msgBox(title, prompt, Browser.Buttons.OK); |
|
|
} |
|
|
} |
|
|
|