unable to access folder just created Google Drive - google-apps-script

I created a script that generates a folder in Google Drive and gets the folder ID of that folder.
Upon trying to access that folder in a unique function I get the error:
no item with the given ID could be found, or you do not have permission to access it on Folder
Please see my script below (called independently from html):
var childFolderIdA;
function doGet() {
return HtmlService.createHtmlOutputFromFile('multifile').setTitle('test – multi upload').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function test(parent,child){
createSharedSubFolder(parent,child);
}
function createSharedSubFolder(parent,child) { // folder names as string parameters
var folders = DriveApp.getFolders();
var exist = false
while (folders.hasNext()) {
var folder = folders.next();
if(folder.getName()==parent){exist = true ; var folderId = folder.getId(); break};// find the existing parent folder
}
if(exist){ //parent folder exists
var child = DriveApp.getFolderById(folderId).createFolder(child).setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT);
var childFolderId = child.getId();
childFolderIdA = childFolderId;
}else{
var childFolder = DriveApp.createFolder(parent).createFolder(child); //create parent and child folders
childFolder.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT);
}
}
function saveFile(data,name,folderName) {
var contentType = data.substring(5,data.indexOf(';'));
var file = Utilities.newBlob(Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)), contentType, name); //does the uploading of the files
DriveApp.getFolderById(childFolderIdA).createFile(file);
}

You can't depend on global variables to save state between calls. Each time you call a script a new script instance is spawned. Each one will maintain its own state.
For example:
google.script.run.createSharedSubFolder(...) --> Script Instance 1..var childFolderIdA=folderId;
google.script.run.saveFile(...) --> Script Instance 2..var childFolderIdA=null;
You can save the the folderId to the users property store:
PropertiesService.getUserProperties().setProperty("childFolderId", childFolderId);
You can retrieve the folder Id:
var folderId = PropertiesService.getUserProperties().getProperty("childFolderId");
Your code with this change:
function doGet() {
return HtmlService.createHtmlOutputFromFile('multifile').setTitle('test – multi upload').setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
function test(parent,child){
createSharedSubFolder(parent,child);
}
function createSharedSubFolder(parent,child) { // folder names as string parameters
var folders = DriveApp.getFolders();
var exist = false
while (folders.hasNext()) {
var folder = folders.next();
if(folder.getName()==parent){exist = true ; var folderId = folder.getId(); break};// find the existing parent folder
}
if(exist){ //parent folder exists
var child = DriveApp.getFolderById(folderId).createFolder(child).setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT);
var childFolderId = child.getId();
PropertiesService.getUserProperties().setProperty("childFolderId", childFolderId);
}else{
var childFolder = DriveApp.createFolder(parent).createFolder(child); //create parent and child folders
childFolder.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.EDIT);
}
}
function saveFile(data,name,folderName) {
var contentType = data.substring(5,data.indexOf(';'));
var file = Utilities.newBlob(Utilities.base64Decode(data.substr(data.indexOf('base64,')+7)), contentType, name); //does the uploading of the files
var childFolderId = PropertiesService.getUserProperties().getProperty("childFolderId");
DriveApp.getFolderById(childFolderId).createFile(file);
}

Related

Google Script DriveApp assistance

I've been using this script that helps me find manage folders on Google drive, by showing empty folders and deleting them.
I'm trying to amend it to specify the starting folder, by ID, using DriveApp.getFolderById('folderID') but I keep getting errors.
This is a section of the original code:
function getEmptyFolders() {
// Get sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('Manage Empty Folders')
if (!sheet) {
SpreadsheetApp.getActive().insertSheet('Manage Empty Folders')
}
var sheet = SpreadsheetApp.getActive().getSheetByName('Manage Empty Folders')
var clearContent = sheet.clear()
var folders = DriveApp.getFolders();
var fileArray = [
["Folder Name", "Folder Id", "Folder URL"]
]
while (folders.hasNext()) {
var folder = folders.next()
// If the folder has no files or child folder in it, call them out.
if (folder.getFiles().hasNext() == false && folder.getFolders().hasNext() == false) {
var name = folder.getName()
var id = folder.getId()
var url = folder.getUrl()
// Push empty folder details into array
fileArray.push([name, id, url])
}
}
// formatting
var headerRow1 = sheet.getRange("A1:C1").setBackground("#d9d9d9").setFontColor("#000000").setFontWeight("Bold")
sheet.setColumnWidths(1, 4, 300)
// write results to the sheet
sheet.getRange(1, 1, fileArray.length, 3).setValues(fileArray)
}
which works great but when I try to change
var folders = DriveApp.getFolders();
to
var folders = DriveApp.getFolderByID('folderID');
I get an error:
TypeError: folders.hasNext is not a function
I'm quite new to Google Script and thought I'd understood the documentation, but obviously not!
Issue
That is because getFolderById(id) returns an object of type folder and as the error also suggests, folder does not have a method hasNext as you can also see in the attached link.
On the other hand, getFolders() returns an object of type FolderIterator which is actually a collection of folder objects and therefore hasNext() is required to iterate over these folders.
Although you can get the folder and iterate over all the subfolders:
var main_folder = DriveApp.getFolderByID('folderID');
var folders = main_folder.getFolders();
Solution:
If you want to use getFolderById then you should remove the while loop. Since you have a single folder there is no need of iterating and in fact it is wrong to do so:
function getEmptyFolders() {
// Get sheet
var sheet = SpreadsheetApp.getActive().getSheetByName('Manage Empty Folders')
if (!sheet) {
SpreadsheetApp.getActive().insertSheet('Manage Empty Folders')
}
var sheet = SpreadsheetApp.getActive().getSheetByName('Manage Empty Folders')
var clearContent = sheet.clear()
// get the parent folder by its id
var main_folder = DriveApp.getFolderById('folderID'); // new code
// get all subfolders
var folders = main_folder.getFolders(); // new code
var fileArray = [
["Folder Name", "Folder Id", "Folder URL"]
]
while (folders.hasNext()) {
var folder = folders.next()
// If the folder has no files or child folder in it, call them out.
if (folder.getFiles().hasNext() == false && folder.getFolders().hasNext() == false) {
var name = folder.getName()
var id = folder.getId()
var url = folder.getUrl()
// Push empty folder details into array
fileArray.push([name, id, url])
}
}
// formatting
var headerRow1 = sheet.getRange("A1:C1").setBackground("#d9d9d9").setFontColor("#000000").setFontWeight("Bold")
sheet.setColumnWidths(1, 4, 300)
// write results to the sheet
sheet.getRange(1, 1, fileArray.length, 3).setValues(fileArray)
}

DriveApp: Get File ID with Parent Folder ID/Name and File Name

I'm trying to use DriveApp to determine a file ID utilizing:
Either the parent folder name, or the parent folder ID
The file name in question
I thought I'd use this:
https://yagisanatode.com/2018/10/05/google-apps-script-get-file-by-name-with-optional-parent-folder-crosscheck/
But it always returns:
There are multiple files named: (filename). But none of them are in folder, (foldername).
...which is not true. Any ideas or any easier way to do this?
Thanks in advance.
Here's a minimal example:
/*
* ****Get File By Name***
*
*param 1: File Name
*param 2: Parent Folder of File (optional)
*
*returns: Dictionary of file "id" and "error" message {"id": ,"error": }
* -if there is no error, "id" returns file id and "error" returns false
* -if there is an error, "id" returns false and "error" returns type of error as a string for user to display or log.
*/
function getFileByName(fileName, fileInFolder){
var filecount = 0;
var dupFileArray = [];
var folderID = "";
var files = DriveApp.getFilesByName(fileName);
while(files.hasNext()){
var file = files.next();
dupFileArray.push(file.getId());
filecount++;
};
if(filecount > 1){
if(typeof fileInFolder === 'undefined'){
folderID = {"id":false,"error":"More than one file with name: "+fileName+". \nTry adding the file's folder name as a reference in Argument 2 of this function."}
}else{
//iterate through list of files with the same name
for(fl = 0; fl < dupFileArray.length; fl++){
var activeFile = DriveApp.getFileById(dupFileArray[fl]);
var folders = activeFile.getParents();
var folder = ""
var foldercount = 0;
//Get the folder name for each file
while(folders.hasNext()){
folder = folders.next().getName();
foldercount++;
};
if(folder === fileInFolder && foldercount > 1){
folderID = {"id":false,"error":"There is more than one parent folder: "+fileInFolder+" for file "+fileName}
};
if(folder === fileInFolder){
folderID = {"id":dupFileArray[fl],"error":false};
}else{
folderID = {"id":false,"error":"There are multiple files named: "+fileName+". \nBut none of them are in folder, "+fileInFolder}
};
};
};
}else if(filecount === 0){
folderID = {"id":false,"error":"No file in your drive exists with name: "+fileName};
}else{ //IF there is only 1 file with fileName
folderID = {"id":dupFileArray[0],"error":false};
};
return folderID;
};
function test() {
//My arguments for the function
var myFileName = "Invoices";
var myFileParentFolderName = "testing";
//Run the function
var getFileID = getFileByName(myFileName, myFileParentFolderName);
//Check if folder exists
if(getFileID.id === false){ //if file cannot be accurately found.
Logger.log(getFileID.error); //alert or log error. Give option to try another FileName
}else{
// If the file ID exists then proceed with the program.
Logger.log(getFileID.id);
};
}
The solution is much simpler than you think.
In the following script, adjust the folderID and fileName to your
particular case and it will store in an array all the IDs if multiple
files exist in this folder with the selected name.
If the file exists only one, then you will get an array of a single element.
Solution:
function findFilesInfo() {
const folderId = 'folderID';
const fileName = 'fileName';
const folder = DriveApp.getFolderById(folderId);
const files = folder.getFilesByName(fileName);
const fileIDs = [];
while (files.hasNext()) {
var file = files.next();
fileIDs.push(file.getId());
}
Logger.log(fileIDs);
}
fileIDs has the list of IDs of the particular fileName under the folder with ID folderID.

duplicate folder and rename file structure

I'm trying to automate my duplicating folder process in google drive. As part of the process, I want to rename files and folders for each new client.
I've adapted some code found previously. It was previously working well, but for some reason now any folders/files that are more than 1 level deep of the root folder come back "undefined" in the replace section of the command.
function duplicatefolder(){
var newclientname = Browser.inputBox('Client Name')
var sourceFolder = "1. Master Client Folder";
var targetFolder = newclientname;
var source = DriveApp.getFoldersByName(sourceFolder);
var target = DriveApp.createFolder(targetFolder);
if (source.hasNext()) {
copyFolder(source.next(), target, newclientname);
}
}
function copyFolder(source, target,client) {
var folders = source.getFolders();
var files = source.getFiles();
while(files.hasNext()) {
var file = files.next();
var newname= file.getName().toString().replace("Master",client)
file.makeCopy(newname, target);
}
while(folders.hasNext()) {
var subFolder = folders.next();
var folderName = subFolder.getName();
var newFolderName = subFolder.getName().replace("Master",client)
var targetFolder = target.createFolder(newFolderName);
copyFolder(subFolder, targetFolder);
}
}
The script also creates the folder in the root directory of google drive. Ideally, I'd like it to be created inside the folder "Clients". How would I add this to the script?
Appreciate the help.
Cheers
Please see attached link hope this is it what you are looking for
https://yagisanatode.com/2018/07/08/google-apps-script-how-to-create-folders-in-directories-with-driveapp/

How can I access last created sub folder and its files in google drive using google-apps-script

I need to access the last created subfolder from a parent folder and subfolder's files but i'm failing to do so. Any help in this regard would be highly appreciated.
I'm trying to get files of the last created folder but it gives me an error.
function myFunction() {
// set the folder to pull folder names from
var parentid = "19mrz1uwYVCnmW1XZJYq3";
var parent = DriveApp.getFolderById(parentid);
var parentfolder= parent.getfolders();
var folders = parentfolder.getLastupdated();
var dd = folders.getfiles();
}
I need to excess the last created subfolder and work on it's content to copy somewhere else.
You can find the newest folder with the JS function reduce() and the Apps Script method getDateCreated().
Sample:
function myFunction() {
var parentid = "19mrz1uwYVCnmW1XZJYq3";
var parent = DriveApp.getFolderById(parentid);
var parentfolder= parent.getFolders();
var array=[];
var arrayFolders=[];
while (parentfolder.hasNext()) {
var folders = parentfolder.next();
array.push(folders.getDateCreated());
arrayFolders.push(folders.getId());
}
var date=array.reduce(function (a, b) {
return a > b ? a : b;
});
var index=array.indexOf(date);
var newestFolder=DriveApp.getFolderById(arrayFolders[index]);
var myFiles=newestFolder.getFiles();
}

List all files and folder in google drive

I've been trying to figure this out for a while now. I hope I can get some guidance on this. The purpose of the following script is to get a full list of folders and files with subfolders and their files included.
Here is what I currently have:
var counter = 0
var files = folder.getFiles();
var subfolders = folder.getFolders();
var folderPath = folder.getName();
while (subfolders.hasNext()){
subfolder = subfolders.next();
var row = [];
//row.push(subfolder.getName(),'',subfolder.getId(),subfolder.getUrl(),subfolder.getSize(),subfolder.getDateCreated(),subfolder.getLastUpdated());
//list.push(row);
if(counter > 0){
var files = subfolder.getFiles();
}
while (files.hasNext()){
file = files.next();
var vals = file.getUrl();
var row = [];
if(counter == 0){
row.push(folder.getName(),file.getName(),file.getId(),file.getUrl(),file.getSize(),file.getDateCreated(),file.getLastUpdated())
}else{
row.push(folderPath + '/' + subfolder.getName(),file.getName(),file.getId(),file.getUrl(),file.getSize(),file.getDateCreated(),file.getLastUpdated())
}
list.push(row);
}
counter = counter + 1
}
It currently gets the folder names and file names for the current folder and it's subfolder. It doesn't go any further than that. I'm stuck trying to figure out how to get a loop going to continue until there are no more sub-folders.
It isn't a very big drive. There are less than 10 levels but would like the flexibility to go further if needed.
Recursion is beneficial in this case. The code below calls the recursive method recurseFolder() which takes a Folder and Array as a parameter. It adds all the files in the folder to a list, then calls itself on any subfolders it finds.
function test(){
var root = DriveApp.getRootFolder();
var list = [];
var list = recurseFolder(root, list);
Logger.log(JSON.stringify(list));
//This is just how I am testing the outputed list. You can do what you need.
var sheet = SpreadsheetApp.getActiveSheet();
list.forEach(function (row){
sheet.appendRow(row);
});
}
function recurseFolder(folder, list){
var files = folder.getFiles();
var subfolders = folder.getFolders();
while (files.hasNext()){ //add all the files to our list first.
var file = files.next();
var row = [];
Logger.log("File: " + folder.getName());
row.push(folder.getName(),file.getName(),file.getId(),file.getUrl(),file.getSize(),file.getDateCreated(),file.getLastUpdated())
list.push(row);
}
while (subfolders.hasNext()){ //Recurse through child folders.
subfolder = subfolders.next();
Logger.log("Folder: " + subfolder.getName());
list = recurseFolder(subfolder, list); //Past the original list in so it stays a 2D Array suitible for inserting into a range.
}
return list;
}
I'm not sure if the output is formatted how you intended so you might need to play with it a little. Note: It will easily time out if run on a larger Drive.
You need a function that will navigate the folder structure recursively, meaning that if it runs into a subfolder within a folder, it will call itself again passing that folder as a new parent.
function listFolders(parentFolderId) {
var sourceFolder = DriveApp.getFolderById(parentFolderId) || DriveApp.getRootFolder();
var folders = sourceFolder.getFolders();
var files = sourceFolder.getFiles();
while (files.hasNext()) {
var file = files.next();
//Do something
}
while (folders.hasNext()) {
var folder = folders.next();
listFolders(folder.getId());
}
}
Note that this function will still time out if you have lots of files in your Drive, in which case you need to store the state of your app using PropertiesService and schedule the function to run again using triggers via the ScriptApp. You can achieve this by saving the continuation token for your Files Iterator between script executions
More on ContinuationToken