Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save phillypb/4ea4381cafc232bcf2612e93113a99f6 to your computer and use it in GitHub Desktop.
Save phillypb/4ea4381cafc232bcf2612e93113a99f6 to your computer and use it in GitHub Desktop.
/*
Global Variables that may need to be tweaked and are easier to access by placing here.
*/
// Maximum runtime of script in minutes to prevent timeout (5 minutes)
var maxRuntime = 5 * 60 * 1000;
/*
This Function gets the necessary data from the spreadsheet.
*/
function getSpreadsheetData() {
try {
// Log information
logEvent('Script has started');
// get spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create toast popup to inform user
ss.toast('Task has now started ...', 'Start');
// get 'Welcome' sheet
var welcomeSheet = ss.getSheetByName('Welcome');
// get folder Id containing Files to be copied
var filesFolderId = welcomeSheet.getRange(5, 4).getValue().trim();
// get folder Id of Parent folder containing subfolders to copy files into
var parentFolderId = welcomeSheet.getRange(9, 4).getValue().trim();
// get value for including subfolder name
var includeName = welcomeSheet.getRange(13, 4).getValue().trim();
// create name:value pair so array easier to work with
var sheetData = { ss: ss, filesFolderId: filesFolderId, parentFolderId: parentFolderId, includeName: includeName };
// run Function to copy files into existing folders
var copyFilesToFoldersFlag = copyFilesToFolders(sheetData);
if (copyFilesToFoldersFlag) {
// no errors occurred during process
// Log information
logEvent('Script has finished without errors');
} else {
// there were errors during process, relevant popup will already be displayed
// Log information
logEvent('Script completed with errors');
}
}
catch (error) {
// there was a problem getting spreadsheet data
logEvent("Error with 'getSpreadsheetData' Function: " + error);
// create popup to inform user
var popupTitle = "'getSpreadsheetData' Function Error";
var popupMessage = "Error message: " + error;
htmlPopup(popupTitle, popupMessage);
}
}
/*
This Function gets the Google Drive folder containing the files to be copied.
It get the Parent Drive folder containg the subfolders to iterate through.
It iterates through each subfolder and makes a copy of the files to be placed into it.
It then optionally appends the subfolder name to new file copy.
*/
function copyFilesToFolders(sheetData) {
try {
// Log information
logEvent("Starting 'copyFilesToFolders' Function");
// extract Sheet data from name:value pair array
var ss = sheetData['ss'];
var filesFolderId = sheetData['filesFolderId'];
var parentFolderId = sheetData['parentFolderId'];
var includeName = sheetData['includeName'];
// Log information
logEvent("Option to append subfolder name is: " + includeName);
// get Google Drive folder containing files to copy
var filesFolder = DriveApp.getFolderById(filesFolderId);
// get Parent Google Drive folder containing subfolders to iterate through
var parentFolder = DriveApp.getFolderById(parentFolderId);
} catch (error) {
// error getting Google Drive folders
logEvent('Error getting Google Drive folders: ' + error.stack);
// create popup to inform user
var popupTitle = "Error getting Google Drive folders";
var popupMessage = "Error message: " + error.stack;
htmlPopup(popupTitle, popupMessage);
// return Flag to Parent Function
return false;
};
// check there are files and subfolders to work through
var filesLength = filesFolder.getFiles().length;
logEvent('Number of files to copy is: ' + filesLength);
var parentFolderLength = parentFolder.getFolders().length;
logEvent('Number of subfolders is: ' + parentFolderLength);
try {
// proceed IF successfully got Google Drive folders
if (parentFolder) {
// Log information
logEvent("Got all Google Drive folders");
// create Counter to log number of copied files
var copiedFilesCounter = 0;
// create Counter to log number of subfolders iterated through
var subfoldersCounter = 0;
// run Function to check Script Properties for 'Continuation Token'
var continuationToken = getScriptProperties();
// check no error getting Script Properties before proceeding ************************
if (continuationToken !== false) {
// get start time so can manage duration of script and avoid timeout
var startTime = new Date().getTime();
} else {
// error occurred, return false flag to Parent Function
return false;
}
// check no error getting Script Properties before proceeding ************************
// check if 'Continuation Token' exists to determine if continuing conversion
if (continuationToken === null) {
// no Token exists so proceed as first time running the script:
// log message in sheet
logEvent('No Continuation Token exists. Copying files ...');
// get all subfolders in Parent Drive folder
var subFolders = parentFolder.getFolders();
} else {
// Token does exist in Script Properties
// log message in sheet
logEvent('Continuation Token does exist. Copying files ...');
// continue iterating through Drive subfolders with Token
var subFolders = DriveApp.continueFolderIterator(continuationToken);
}
// cycle through each subfolder
while (subFolders.hasNext()) {
// get subfolder
var subFolder = subFolders.next();
// get subfolder name
var subFolderName = subFolder.getName();
// create toast popup to inform user and log
ss.toast('Folder: ' + subFolderName, 'Copying files into it ...');
logEvent('Folder: ' + subFolderName + ' Copying files into it ...');
// iterate through files and copy into subfolder ****************************************
// get all files in folder - need to do here so 'while' loop refreshes after each iteration
var filesToCopy = filesFolder.getFiles();
// cycle through each file
while (filesToCopy.hasNext()) {
// get file
var file = filesToCopy.next();
// check what user selected for including the subfolder name in file *****************
var fileName = file.getName();
logEvent("File name to copy is: " + fileName);
if (includeName == 'Append subfolder name') {
// append file name
fileName = fileName + " - " + subFolderName;
} else if (includeName == 'Prepend subfolder name') {
// prepend file name
fileName = subFolderName + " - " + fileName;
} else {
// user did not select to include subfolder name to file
};
// check what user selected for including the subfolder name in file *****************
// make copy of file into subfolder
file.makeCopy(fileName, subFolder);
// increment Counter by 1 to log number of copied files
copiedFilesCounter++;
};
// iterate through files and copy into subfolder ****************************************
// increment Counter by 1 to log number of subfolders iterated through
subfoldersCounter++;
// *************************** perform runtime check ***************************
// get current time
var endTime = new Date().getTime();
// find elapsed time by subtracting from start time
var elapsedTime = endTime - startTime;
// check against maximum runtime
var timeLimitExceeded = elapsedTime >= maxRuntime;
// check status of runtime
if (timeLimitExceeded) {
// runtime has been met/exceeded, store 'Continuation Token' so can resume later
// log message in sheet
logEvent('Runtime has been met/exceeded.');
// get Token from last subfolder
var continuationToken = subFolders.getContinuationToken();
/*
run Function to add Token to Script Properies for use later.
capture in error variable as this is the last step in process anyway,
so no matter what will be using 'break'
*/
setPropertyFlag = setScriptProperties(continuationToken);
if (setPropertyFlag) {
// successfully completed
// break out of loop to prevent script from continuing
break;
} else {
// problem occurred, return false Flag
return false;
}
} else {
// runtime has not been met/exceeded, script can continue looping through files
}
// *************************** perform runtime check ***************************
};
// Log information
logEvent("Completed copying files into a total of " + subfoldersCounter + " subfolders");
logEvent("Created " + copiedFilesCounter + " files from the copy");
} else {
// do nothing as script will have terminated at this point
}
// check if there are still subfolders to iterate through
if (subFolders.hasNext()) {
// yes there are subfolders to iterate through
// log message in sheet
logEvent('Successfully iterated through ' + subfoldersCounter + ' subfolders.');
// log message in sheet
logEvent('There are still subfolders left.');
// no errors have occurred in the script
var popupTitle = 'Runtime reached - ' + subfoldersCounter + ' subfolders iterated through';
var popupMessage = 'No errors, but there are still subfolders to iterate through, so you may wish to run this tool again.';
htmlPopup(popupTitle, popupMessage);
// log message in sheet
logEvent('Script completed without errors.');
// return success Flag
return true;
} else {
// no all subfolders have been iterated through
// delete Script Properties of Token as no longer required
deletePropertyFlag = deleteScriptProperties('CONTINUATION_TOKEN');
// check no error deleting Script Property before proceeding ***********
if (deletePropertyFlag) {
// log message in sheet
logEvent('All subfolders have been iterated through.');
// no errors have occurred in the script
var popupTitle = 'Tool complete - ' + subfoldersCounter + ' subfolders iterated through';
var popupMessage = 'No errors. All files have been copied into all subfolders.';
htmlPopup(popupTitle, popupMessage);
// return success Flag
return true;
}
else {
// error deleting Script Property - do nothing as popup will already be displayed
}
// check no error deleting Script Properties before proceeding ***********
}
} catch (error) {
// there was a problem during file copying
logEvent('Error during file copying: ' + error.stack);
// create popup to inform user
var popupTitle = "Error during file copying";
var popupMessage = "Error message: " + error.stack;
htmlPopup(popupTitle, popupMessage);
return false;
}
}
/*
Function to look for 'Continuation Token' in Script Properties.
https://developers.google.com/apps-script/guides/properties
*/
function getScriptProperties() {
try {
// log message in sheet
logEvent('Getting Script Properties.');
// access Script Properties
var scriptProperties = PropertiesService.getScriptProperties();
// look for 'Continuation Token' Property
var continuationToken = scriptProperties.getProperty('CONTINUATION_TOKEN');
// return value to Parent Function
return continuationToken;
}
catch (error) {
// log error in sheet
logEvent('Problem getting Script Properties: ' + error);
// display user popup to inform of error
var popupTitle = 'Get Script Properties error';
var popupMessage = 'Problem getting Script Properties: ' + error;
htmlPopup(popupTitle, popupMessage);
// return false to Parent Function
return false;
}
}
/*
Function to set 'Continuation Token' in Script Properties.
https://developers.google.com/apps-script/guides/properties
*/
function setScriptProperties(continuationToken) {
try {
// log message in sheet
logEvent('Setting Script Properties.');
// access Script Properties
var scriptProperties = PropertiesService.getScriptProperties();
// set 'Continuation Token' Script Property
var continuationToken = scriptProperties.setProperty('CONTINUATION_TOKEN', continuationToken);
// log message in sheet
logEvent('Successfully set Script Properties.');
// return true to Parent Function
return true;
}
catch (error) {
// log error in sheet
logEvent('Problem setting Script Property: ' + error);
// display user popup to inform of error
var popupTitle = 'Set Script Property error';
var popupMessage = 'Problem setting Script Property: ' + error;
htmlPopup(popupTitle, popupMessage);
// return false to Parent Function
return false;
}
}
/*
Function to delete 'Continuation Token' in Script Properties.
https://developers.google.com/apps-script/guides/properties
*/
function deleteScriptProperties(property) {
try {
// log message in sheet
logEvent('Deleting Script Properties.');
// access Script Properties
var scriptProperties = PropertiesService.getScriptProperties();
// delete 'Continuation Token' Property
scriptProperties.deleteProperty(property);
// log message in sheet
logEvent('Successfully deleted Script Properties.');
// return true to Parent Function
return true;
}
catch (error) {
// log error in sheet
logEvent('Problem deleting Script Property: ' + error);
// display user popup to inform of error
var popupTitle = 'Delete Script Property error';
var popupMessage = 'Problem deleting Script Property Token: ' + error;
htmlPopup(popupTitle, popupMessage);
// return false to Parent Function
return false;
}
}
/*
Reset all data within Google Sheet to be able to start afresh.
*/
function reset() {
try {
// log that reset Function has been selected
logEvent("Initiated 'Reset' Function");
// get Spreadsheet UI
var ui = SpreadsheetApp.getUi();
// create Alert popup box
var result = ui.alert(
'Reset spreadsheet',
'Do you wish to remove all inputted information to start again?',
ui.ButtonSet.OK_CANCEL
);
// process user response from Popup Box
if (result == ui.Button.OK) {
// log selection
logEvent("Selected 'OK' to reset spreadsheet");
// get current spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get Welcome sheet
var welcomeSheet = ss.getSheetByName('Welcome');
// clear source folder ID box
welcomeSheet.getRange(5, 4).clearContent();
// clear destination folder ID box
welcomeSheet.getRange(9, 4).clearContent();
// clear delete select box
welcomeSheet.getRange(13, 4).clearContent();
// delete Script Properties of Token
deletePropertyFlag = deleteScriptProperties('CONTINUATION_TOKEN');
// log completion of Function
logEvent("Completed 'Reset' Function.");
// display alert popup to user to confirm completion
ui.alert('Successfully cleared all sheet data.');
}
else {
// User clicked 'No' or 'X' in title bar so do nothing
logEvent("Selected 'CANCEL' to reset spreadsheet");
}
}
catch (error) {
// problem clearing sheet data
logEvent("Problem with 'reset' Function" + error + error.stack);
// run Function to launch HTML popup
var popupTitle = "'reset' Function error";
var popupMessage = "Unable to clear sheet data: " + error;
htmlPopup(popupTitle, popupMessage);
}
}
/*
Function to output messages to the 'Log' sheet.
Can be called anywhere else in script.
*/
function logEvent(action) {
// get the user running the script
var theUser = Session.getActiveUser().getEmail();
// get the relevant spreadsheet to output log details
var ss = SpreadsheetApp.getActiveSpreadsheet();
var logSheet = ss.getSheetByName('Log');
// create and format a timestamp
var dateTime = new Date();
var timeZone = ss.getSpreadsheetTimeZone();
var niceDateTime = Utilities.formatDate(dateTime, timeZone, "dd/MM/yy @ HH:mm:ss");
// create array of data for pasting into log sheet
var logData = [niceDateTime, theUser, action];
// append details into next row of log sheet
logSheet.appendRow(logData);
}
/*
This Function creates a menu item to run this script.
*/
function onOpen() {
SpreadsheetApp.getUi()
.createMenu('Admin')
.addItem('Start now', 'getSpreadsheetData') // label for menu item, name of function to run.
.addItem('Reset sheet', 'reset') // label for menu item, name of function to run.
.addToUi();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment