Google Drive API V3 - Copy function not copying contents - google-drive-api

I've been working on a project to 'duplicate' a Team Drive. I've got the application successfully recreating the entire drive structure and copying files who's mimetype is not a Google folder. My issue is that the contents of copied files are not being copied as well.
I'm using Node for the application, with the Google Drive API SDK.
await drive
.files
.copy({
fileId: file.id,
supportsAllDrives: true,
requestBody: {
name: Mustache.render(originalFile.name, data),
driveId: driveId,
parents: [
parentId
],
mimeType: originalFile.mimeType
}
})
.then(res => {
newFile = res.data;
})
.catch(e => {
logger.error("Issue copying a file: ", e);
});
So while the above functions as expected (adjusting the name of the new file, putting it in the correct parent folder, under the correct new drive ID), there is no content in these copied files.
For a more specific example, let's say that one of the files I'm copying is a PDF. The new PDF with the correct mimetype shows in my new Team Drive, but when opening it (in browser, or downloading), there's nothing at all there. See some screenshots for what I mean.
Original Drive and file, note the size:
New Drive file, with no size/content:
Edit1:
I tried using the API explorer as a proof of concept again. It works as expected, copying the content. Tried it twice, first to the same folder in the same Team drive, then created a new team drive with a subfolder. Content copied fine in both cases.
In the case that it matters, here's the request for creating the new drive as well. requestId is just a random guid using the Chance repo.

The only error source I can imagine is mimeType
You do not need to specify the mimeType if you only want to copy a file without converting it.
Try a simple request without the request body:
drive.files.copy(
{
fileId: file.id,
requestBody: {}
},
(err, res) => {
if (err) return console.log(("Issue copying a file: " + err);
newFile = res.data;
console.log(newFile);
}
);
Once you confirm that it works correctly, add parameters one by one.

Related

Rename and move a file in Team Drive [duplicate]

I am creating a workflow for Shared Drive (Team Drive) where I have 3 folders under team drive:
TO BE APPROVED
APPROVED
REJECTED
I am sending a document from TO BE APPROVED folder for approval, if user approves it then this document should move to APPROVED folder. Same logic for REJECTED.
Now my question is how can I move a document between Shared Drive folders. DriveApp.getFolderById(folderId).addFile() is not working as I can not have more than one parent in Team Drive. DriveApp.getFolderById(folderId).createFile() is working but it is creating a whole new file with new ID which is not fulfilling my purpose of approval workflow as this is a whole new file.
Is there any way to move file or copy/replace any operations which will not change my file's ID? I tried for REST APIs as well but couldn't found any.
Okay looks like I found an answer, via REST API I can update file's parents. I've made that call and it's working.
Here's the sample.
var apiUrl = "https://www.googleapis.com/drive/v3/files/fileId?addParents=newFolderId&removeParents=oldFolderId&supportsTeamDrives=true";
var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method":"PATCH",
"headers": header
};
var res = UrlFetchApp.fetch(apiUrl, options);
UPDATE
Using Advance Services API we can achieve the same, here's the answer I've received from Aliaksei Ivaneichyk
function moveFileToFolder(fileId, newFolderId) {
var file = Drive.Files.get(fileId, {supportsTeamDrives: true});
Drive.Files.patch(file, fileId, {
removeParents: file.parents.map(function(f) { return f.id; }),
addParents: [newFolderId],
supportsTeamDrives: true
});
}
Here you need to Enable Drive SDK advance services if you are using Appscript. In case of Appmaker Add Drive SDK as Service in Settings Option.

File movement between Google Shared Drive (team drive) folders using Apps Script

I am creating a workflow for Shared Drive (Team Drive) where I have 3 folders under team drive:
TO BE APPROVED
APPROVED
REJECTED
I am sending a document from TO BE APPROVED folder for approval, if user approves it then this document should move to APPROVED folder. Same logic for REJECTED.
Now my question is how can I move a document between Shared Drive folders. DriveApp.getFolderById(folderId).addFile() is not working as I can not have more than one parent in Team Drive. DriveApp.getFolderById(folderId).createFile() is working but it is creating a whole new file with new ID which is not fulfilling my purpose of approval workflow as this is a whole new file.
Is there any way to move file or copy/replace any operations which will not change my file's ID? I tried for REST APIs as well but couldn't found any.
Okay looks like I found an answer, via REST API I can update file's parents. I've made that call and it's working.
Here's the sample.
var apiUrl = "https://www.googleapis.com/drive/v3/files/fileId?addParents=newFolderId&removeParents=oldFolderId&supportsTeamDrives=true";
var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method":"PATCH",
"headers": header
};
var res = UrlFetchApp.fetch(apiUrl, options);
UPDATE
Using Advance Services API we can achieve the same, here's the answer I've received from Aliaksei Ivaneichyk
function moveFileToFolder(fileId, newFolderId) {
var file = Drive.Files.get(fileId, {supportsTeamDrives: true});
Drive.Files.patch(file, fileId, {
removeParents: file.parents.map(function(f) { return f.id; }),
addParents: [newFolderId],
supportsTeamDrives: true
});
}
Here you need to Enable Drive SDK advance services if you are using Appscript. In case of Appmaker Add Drive SDK as Service in Settings Option.

get file content of google docs using google drive API v3

Is there any way to get the content of native files (Google Docs) using Google Drive API v3? I know API v2 supports this with the exportLinks property, but it doesn't work anymore or has been removed.
You can also download files with binary content (non google drive file) in Drive using the webContentLink attribute of a file. From https://developers.google.com/drive/v3/reference/files:
A link for downloading the content of the file in a browser. This is
only available for files with binary content in Drive.
An example (I use method get() to retrieve the webContentLink from my file):
gapi.client.drive.files.get({
fileId: id,
fields: 'webContentLink'
}).then(function(success){
var webContentLink = success.result.webContentLink; //the link is in the success.result object
//success.result
}, function(fail){
console.log(fail);
console.log('Error '+ fail.result.error.message);
})
With google drive files, the export method can be used to get those files: https://developers.google.com/drive/v3/reference/files/export
This method needs an object with 2 mandatory attributes (fileId, and mimeType) as parameters.
A list of available mimeTypes can be seen here or here (thanks to #ravioli)
Example:
gapi.client.drive.files.export({
'fileId' : id,
'mimeType' : 'text/plain'
}).then(function(success){
console.log(success);
//success.result
}, function(fail){
console.log(fail);
console.log('Error '+ fail.result.error.message);
})
You can read non google doc file content (for example a text file) with gapi.client.drive.files.get with alt:"media". Official example. My example:
function readFile(fileId, callback) {
var request = gapi.client.drive.files.get({
fileId: fileId,
alt: 'media'
})
request.then(function(response) {
console.log(response); //response.body contains the string value of the file
if (typeof callback === "function") callback(response.body);
}, function(error) {
console.error(error)
})
return request;
}
For v3 of the api, you can use the export method https://developers.google.com/drive/v3/reference/files/export
If you use files.export, you won't get any link that will let you download the file as stated in v3 Migration guide.
For example using the the try-it, I only got a MiMetype response but no downloadable link:
[application/vnd.oasis.opendocument.text data]
Workaround for this is a direct download. Just replace FILE_ID with your Google Doc fileID and execute it in the browser. Through this, I was able to export Google docs files.
https://docs.google.com/document/d/FILE_ID/export?format=doc
Credits to labnol's guide for the workaround.

Google Drive Advanced API - Insert File cause Exception: Empty response

I've newer from Google Script and trying to establish a script supporting anonymous upload to Drive (https://ctrlq.org/code/19747-google-forms-upload-files).
What I've done so far is able to run the script and found out folder.createFile(blob) function cannot upload with filesize more than 10Mb. I then found out using Advanced Drive Service(Drive API) may able to provide the fix, so I change using Advanced Service(Drive rather than DriveApp) (https://developers.google.com/drive/v2/reference/files/insert#http-request). However, It then response the error Exception: Empty response.
Here is my code.
function uploadFiles(form) {
try {
var blob = form.file;
var contentType = blob.type;
var folderName = "Upload Folder";
var folder, folders = DriveApp.getFoldersByName(folderName);
if (folders.hasNext()) {
folder = folders.next();
} else {
folder = DriveApp.createFolder(folderName);
}
var file = {
title: blob.name,
mimeType: contentType,
parents:[{id:folder.getId()}]
};
var options = {
uploadType: "multipart"
};
file = Drive.Files.insert(file, blob, options);
return "File uploaded successfully " + file.fileSize;
} catch (error) {
return error.toString();
}
}
It can upload <10Mb file by using above code(on both uplaodType: media and multipart). However, >10Mb still failed, would it be needed to use resumable?
Remark: I've noticed there was a question similar to the issue I've encountering(Advanced Drive Service returning Empty Response Error when inserting file), but seems there is no conclusion at that point, so I wish somebody can help fixing this issue
As stated in the answer on the similar post you included, it is being advised to use uploadType=resumable since the file size being uploaded is high. It pretty much is the solution to your issue. As per the Upload Files document:
Simple upload
For quick transfer of smaller files, for example, 5 MB or less.
Resumable upload
For reliable transfer, especially important with larger files.

Google Drive API: Cannot copy a shared file

I have an application that copies files from one account to another using the Drive Api.
It first share the documents form source account to destination and then on destination makes a local copy of the shared file.
I has worked wel for some accounts until now. I have an account that the aplication can't copy the file. I get an authentication error such as the following:
{ errors:
[ { domain: 'global',
reason: 'userAccess',
message: 'The authenticated user does not have the required access to the file PKb_fEw17FE',
locationType: 'header',
location: 'Authorization' } ],
code: 403,
message: 'The authenticated user does not have the required access to the file PKb_fEw17FE' }
A few important things:
The file descriptor in the error is not file_id the application tries
to copy. In fact It changes every time you try to copy the file.
The same error ocurrs when I try to do it manually using the Api
explorer on the Drive developers
site(https://developers.google.com/drive/v2/reference/files/copy)
I verified through the GUI and using the API explorer that the
user that is making the copy has the proper permissions.
When I do the copy using the Web Gui, it works without problems.
Could this be related to quotas?
An aditional piece of information:
The requests body for the copy only includes the title for the new file. See the code below(nodejs)
var body = {'title': file.title };
var request = client.drive.files.copy({'fileId': file.id}, body);
request.withAuthClient(auth2).execute(function (err, resp)
Found the problem. It seems that when you copy a file without declaring the parent It sometimes copy it to the Root dir and some times tries to copy it in another place(I presume with the same parent as the original one).
I specified that all files should be copied to the root forlder adding the ID for the parent and the problem was solved.
var body = {'title': file.title,
'parents': [ {'id': wr_new_parentroot} ]
};
console.log('Request Body: %j', body);
var request = client.drive.files.copy({'fileId': file.id}, body);
request.withAuthClient(auth2).execute(function (err, resp) {