3

I have a code to get the parent folder of my GoogleSheet by using this code

var ssId = SpreadsheetApp.getActiveSpreadsheet().getId(); //get my GSheet ID
var parentFolder = DriveApp.getFileById(ssId).getParents().next(); //get the parent folder name

I've already share the base folder to the whole organization with editor rights.

Running the app by me it is running without any issue.

But when my colleague run the app, it is getting this error.

Exception: Cannot retrieve the next object: iterator has reached the end.

tried hasNext()

var ssId = SpreadsheetApp.getActiveSpreadsheet().getId(); //get my GSheet ID
var parentFolder = DriveApp.getFileById(ssId).getParents(); //get the parent folder

    while (parentFolder .hasNext()) {
      var temp1 = parentFolder .next();
      Logger.log("Temp : "+temp1)
    }

this is not returning anything from other users.

Any idea is this something to do with Google Permission Security issue or anything I've missed?


Edit Code Snippet

Code.gs

function doGet(request) {
 return HtmlService.createTemplateFromFile('CustomerForm').evaluate().setTitle("Demo Form");
}

function uploadFile(vFolder,vFile ,vdata){
  //upload folder
  var drivepath = uploadFiletoDrive(vFolder);

  var contentType = vdata.substring(5,vdata.indexOf(';')),
        bytes = Utilities.base64Decode(vdata.substr(vdata.indexOf('base64,')+7)),
        blob = Utilities.newBlob(bytes, contentType, vFile);
  var folder = DriveApp.getFolderById(drivepath);  
  var file = folder.createFile(blob);

  return file.getId();
}

function uploadFiletoDrive(folderName){
 
  const ssId = SpreadsheetApp.getActiveSpreadsheet().getId();
  const parentFolder = DriveApp.getFileById(ssId).getParents().next(); // get the parent folder location
  
  Logger.log(ssId)
  Logger.log(parentFolder)
 
  const subFolders = parentFolder.getFolders();
  while (subFolders.hasNext()) {
    let folder = subFolders.next();
 
    // Returns the existing folder if found.
    Logger.log(folder.getName())
    if (folder.getName() === folderName) {
      Logger.log("Folder exists")
      Logger.log("Folder SSID : "+folder.getId())
      return folder.getId();
    }
  }
  // Creates a new folder if one doesn't already exist.
   Logger.log("Folder Creating")
   //creating the folder if not exists and will put the description
  folder = parentFolder.createFolder(folderName);
   Logger.log("New Folder SSID : "+folder.getId())
  return folder.getId(); 
}

CustomerForm.html

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
    <table>
      <tr>
        <td> Folder Name : </td>
        <td> <input type="text" id="FolderName"> </td>
      </tr>
      <tr>
        <td> Input File : </td>
        <td> <input type='file' id="FileAttach"></td>
      </tr>
      <tr>
        <td>
          <button type="submit" id="SubmitFile" onclick="submitForm()" >Submit</button>
        </td>
      </tr>
    </table>

  </body>
</html>

<script>
  function submitForm(){
    var myFile =  document.getElementById('FileAttach').files;
    var myFolder = document.getElementById('FolderName').value;
    var reader = new FileReader();
    tempFile = myFile[0];

    if(tempFile){
        reader.readAsDataURL(tempFile);
        reader.onloadend = function(e) {
          if (e.target.error != null) {
            alert("File " + tempFile.name + " could not be read.");
            return;
          } else {
            google.script.run.withSuccessHandler(finishUpload).uploadFile(myFolder, tempFile.name, e.target.result);
          }
        }; 
      }
  }

  function finishUpload(vFileID){
    alert("Uploaded File ID is "+vFileID)
  }

</script>
WaiYuen
  • 35
  • 6
  • In your situation, are you the owner of the spreadsheet and the script? And, the user has permission for reading or writing the parent folder of the Spreadsheet? And, how is your script run by the user? – Tanaike Jun 08 '22 at 02:21
  • Yes. I'm the owner of the spreadsheet and the script. I've given editing rights for organization wide. I've created a web app that will upload a file to GDrive. So this app will check get the parent folder and check if there are the colleague personal folder before uploading the file to their own folder. – WaiYuen Jun 08 '22 at 03:02
  • Thank you for replying. I understood `I'm the owner of the spreadsheet and the script. I've given editing rights for organization wide.`. But, unfortunately, I cannot understand your situation from `I've created a web app that will upload a file to GDrive. So this app will check get the parent folder and check if there are the colleague personal folder before uploading the file to their own folder.`. I apologize for this. Can I ask you about the detail of it? – Tanaike Jun 08 '22 at 03:07
  • Sure. I've created a Web App. In this Web App user will fill up a form and submit with a attachment. My code will get the current SpreadSheet ID and get the Parent folder name. – WaiYuen Jun 08 '22 at 03:17
  • 1
    Thank you for replying. From your reply, I understood that the user runs your script through the Web Apps. In this case, can I ask you about the setting of `Execute as:` and `Who has access to the app:` of your Web Apps? I suppose that you are using V8 runtime. – Tanaike Jun 08 '22 at 03:19
  • Thanks. Below is the appscript.json file. `{ "timeZone": "Australia/Perth", "dependencies": {}, "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8", "webapp": { "executeAs": "USER_ACCESSING", "access": "DOMAIN" }, "oauthScopes": [ "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/userinfo.email", "https://www.googleapis.com/auth/script.send_mail" ] }` – WaiYuen Jun 08 '22 at 03:33
  • Thank you for replying and adding the information. Although I cannot confirm whether the parent folder of your Spreadsheet is shared with the user, from your additional information and your current issue, I guessed that the reason for your issue might be due to `"executeAs": "USER_ACCESSING"` while you are the owner of Google Spreadsheet. In this case, when the user cannot access the parent folder of your Google Spreadsheet, your current issue might occur. – Tanaike Jun 08 '22 at 03:47
  • For example, how about modifying `"executeAs": "USER_ACCESSING"` to `"executeAs": "USER_DEPLOYING"` (In this case, it's `Me`.)? And, how about sharing the parent folder with the user? – Tanaike Jun 08 '22 at 03:47
  • the current Hierarchy is BigFolder > ParentFolder > SpreadSheet . I've already shared the BigFolder to whole organization wide with Editing rights. The Code Snippet will only be accessing ParentFolder which it is already given the rights. – WaiYuen Jun 08 '22 at 05:18
  • Thank you for replying. From `the current Hierarchy is BigFolder > ParentFolder > SpreadSheet . I've already shared the BigFolder to whole organization wide with Editing rights. The Code Snippet will only be accessing ParentFolder which it is already given the rights.`, when you changed the setting of your Web Apps, what result did you obtain? – Tanaike Jun 08 '22 at 08:27
  • @Tanaike, lets discuss beside. I've send an email to your hotmail. Will post back here when we have the solution. – WaiYuen Jun 09 '22 at 02:26
  • Hi, consider responding to Tanaike's questions here too, this might be interesting for other users, and there might be other users who can help you here. – Iamblichus Jun 09 '22 at 08:22
  • `when you changed the setting of your Web Apps, what result did you obtain?` as mentioned even when shared to organization wide with editing role , I'm still getting the same error when user use the Web Apps. – WaiYuen Jun 09 '22 at 09:34
  • Hi, did you test the webapp with `executeAs: Me`, as suggested by Tanaike? In any case, it doesn't make much sense that other users cannot access this, if they have edit access to the parent folder. So, can you double-check that they have access to the parent folder? – Iamblichus Jun 10 '22 at 08:16
  • @lamblichus, yea. i've tried `executeAs: Me` and it is working fine. But the folder creation will be under my email. We would like to know the person who created the new file upload and it should be able to log the person who access the form, hence I've change to `executeAs : USER_ACCESSING`. I've also checked that users are able to access to the parent folder. Send them the sharable link manually and they are able to create, modify, delete. – WaiYuen Jun 13 '22 at 03:40
  • Can you provide a [minimal reproducible example](https://stackoverflow.com/help/minimal-reproducible-example)? – Iamblichus Jun 13 '22 at 08:48
  • Edited my question with the code snippet. Running this app As me is ok. But by user in my organization will give the error – WaiYuen Jun 13 '22 at 10:21
  • Hi, this is unlikely to be reproducible using the code snippet you provided. If users have access to the immediate parent of spreadsheet `ssId`, `DriveApp.getFileById(ssId).getParents().next();` should not fail. Therefore, consider providing a set of reproduction steps for this, including how did you grant users access to the parent folder. – Iamblichus Jun 14 '22 at 08:35
  • I'm using this code to run the process with my colleague and the error is happening with this simple example. The code is able to give the ssId but it will have the error at next(). For this example I have my GSheet inside the `MainFolder` which I've shared at the `MainFolder`. MainFolder -> Share -> Get link -> change -> Change to 'Editor'. "Anyone in this group with this link can edit" – WaiYuen Jun 15 '22 at 01:32
  • 1
    Hi, I posted an answer explaining this issue, I hope this is helpful to you. – Iamblichus Jun 20 '22 at 07:02

1 Answers1

0

Based on your last comment MainFolder -> Share -> Get link -> change -> Change to 'Editor'. "Anyone in this group with this link can edit", I understood that you are sharing the folder with your domain.

Issue:

Due to a relatively recent security update (see Reference below), and since the folder is shared via type=domain, users need to provide the resourceKey the first time they access it.

For example, if users try to access the share link on the browser, and the share link doesn't include the resourceKey, they won't be able to access it if they haven't done it before. The resourceKey is included in the share link, when sharing the files, like this:

https://drive.google.com/drive/folders/{FILE_ID}?resourcekey={RESOURCE_KEY}

Therefore, it is not accessible via File.getParents() if it hasn't been previously accessed, nor via Drive API's Parents.list.

Possible workarounds:

Here are possible alternatives to solve this:

  • If you are an admin, you can remove the security update, so resourceKey is not required.
  • Change the sharing settings so that the folder is directly shared with your desired users instead of the whole domain.
  • Make the users access the folderbefore executing this, either via browser (using the full share link, including resourceKey), or programmatically, using DriveApp.getFolderByIdAndResourceKey(id, resourceKey). In this case, an option would be to change your current code workflow, so that your parent folder is retrieved directly, instead of as a parent of the active spreadsheet.

Reference:

Iamblichus
  • 18,540
  • 2
  • 11
  • 27
  • Thanks @lamblichus for the answer. I'm not able to test out your solution as I'm not the Admin for the GSuite for my organization. And to get that approve will take too long to try. From what you've explained on the recent security update from Google might be the issue that I'm facing. I've mark this as the solution. Maybe someone that have control of your GSuite can try this to confirm it. Thanks anyway – WaiYuen Jun 23 '22 at 06:25