Drive.Files.Copy and “parents” not working

2019-08-19 02:40发布

问题:

I'm trying to copy a file in Team Drives to a new folder location, also in Team Drives. I get a "File not found" error on the last line of code. The newFileID has been checked using DriveApp.getFileByID and by testing in Google API Try-It.

I think the "parents" piece is incorrectly formed. When I try Google API Try-It, the file is copied into the correct folder. Yay! So what's wrong with the Google Script code?

https://developers.google.com/drive/api/v3/reference/files/copy#try-it

Google Script code (not working):

function test() {

  // find Teacher's Learner Guides folder
  var destinationFolderId = "1qQJhDMlHZixBO9KZkkoSNYdMuqg0vBPU";

  var newFile = {
    "name": "Learner Guide - test",
    "description": "New student learner guide",
    "parents": [destinationFolderId]
  };

  // create duplicate document
  var newFileID = "1g6cjUn1BWVqRAIhrOyXXsTwTmPZ4QW6qGhUAeTHJSUs";
  var newDoc = Drive.Files.copy(newFile, newFileID);

}

The Google API Try-It code works. Here's the javascript (working):

return gapi.client.drive.files.copy({
      "fileId": "1g6cjUn1BWVqRAIhrOyXXsTwTmPZ4QW6qGhUAeTHJSUs",
      "supportsTeamDrives": true,
      "resource": {
        "parents": [
          "1qQJhDMlHZixBO9KZkkoSNYdMuqg0vBPU"
        ],
        "name": "Learner Test2"
      }
    })

What would be an efficient and/or correct way of using Drive.Files.Copy in Google Script code to place the copied file into a different folder?

回答1:

The parents metadata associated with the request expects a ParentReference resource for Drive API v2, which is at minimum an object with an id property and the associated fileId, e.g. {id: "some id"}.

Since you are working with Team Drives, you must tell Google that you (i.e. your code) know how to handle the associated differences between regular & Team Drives, with the supportsTeamDrives optional parameter.

Note:

A parent does not appear in the parents list if the requesting user is a not a member of the Team Drive and does not have access to the parent. In addition, with the exception of the top level folder, the parents list must contain exactly one item if the file is located within a Team Drive.

Assuming the code runner meets the criteria, the most simple code to copy a given file to a given Team Drive folder is:

function duplicate_(newName, sourceId, targetFolderId) {
  if (!newName || !sourceId || !targetFolderId)
    return;
  const options = {
    fields: "id,title,parents", // properties sent back to you from the API
    supportsTeamDrives: true, // needed for Team Drives
  };
  const metadata = {
    title: newName,
    // Team Drives files & folders can have only 1 parent
    parents: [ {id: targetFolderId} ],
    // other possible fields you can supply: 
    // https://developers.google.com/drive/api/v2/reference/files/copy#request-body
  };

  return Drive.Files.copy(metadata, sourceId, options);
}

Additional reading:

  • Standard Query Parameters (these can always be passed in the optional argument)
  • Partial Responses (aka "fields")


回答2:

Here's the solution for copying files in Team Drives. @tehhowch had an important piece about needing the optional parameters (you need to use all three parameters for copy API v2). Then the "parents" argument requires a File object, not a string. The code below works by copying the file and moving it into another Team Drives folder.

function test() {

  // find Teacher's Learner Guides folder
  var destFolderId = "1qQJhDMlHZixBO9KZkkoSNYdMuqg0vBPU";
  var originalDocID = "1g6cjUn1BWVqRAIhrOyXXsTwTmPZ4QW6qGhUAeTHJSUs";
  var destFolder = Drive.Files.get(destFolderId, {"supportsTeamDrives": true});

  var newFile = {
    "fileId": originalDocID,
    "parents": [
      destFolder // this needed to be an object, not a string
    ]
  };
  var args = {
    "resource": {
      "parents": [
        destFolder // this needed to be an object, not a string
      ],
      "title": "new name of document here"
    },
    "supportsTeamDrives": true
  };

  // create duplicate Learner Guide Template document
  var newTargetDoc = Drive.Files.copy(newFile, originalDocID, args);
}