How I can manage the sharing-feature: "Disable Copying and downloading" without the advanced Drive Service?
Currently I solve it about:
function mySolveAboutAdvancedService(id) {
var file = Drive.Files.get(id);
file.labels.restricted = true;
Drive.Files.update(file, id);
}
Why I can change all settings but not this one without the advanced Drive Service?
Thanks
You want to achieve the following script without using Advanced Google services.
var file = Drive.Files.get(id);
file.labels.restricted = true;
Drive.Files.update(file, id);
You want to know the reason that "Disable Copying and downloading" cannot be achieved without using above script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Issue and workaround:
Drive API of Advanced Google services uses Drive API v2. In this case, labels.restricted is for Drive API v2, and also, the official document says as follows.
labels.restricted: Warning: This item is deprecated. Deprecated - use copyRequiresWriterPermission instead.
By this, when {labels: {restricted: true}} is used for Drive API v3, it cannot be used while no error occurs. But, when Drive API v2 is used with UrlFetchApp, {labels: {restricted: true}} can be still used. By this, your script using Drive API of Advanced Google service works.
In order to achieve your script without using Advanced Google services, please directly request to the endpoint of Drive API v3 (in this case, v3 is used.) with the request body of {copyRequiresWriterPermission: true} using UrlFetchApp. The sample script is as follows.
Sample script:
function mySolveAboutAdvancedService() {
var id = "###"; // Please set the file ID.
var url = "https://www.googleapis.com/drive/v3/files/" + id;
var params = {
method: "patch",
contentType: "application/json",
payload: JSON.stringify({copyRequiresWriterPermission: true}),
headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
}
Note:
If you want to use Drive API v2 with UrlFetchApp, how about the following script? At Drive API v2, both {labels: {restricted: true}} and {copyRequiresWriterPermission: true} can be used.
function mySolveAboutAdvancedService() {
var id = "###"; // Please set the file ID.
var url = "https://www.googleapis.com/drive/v2/files/" + id;
var params = {
method: "put",
contentType: "application/json",
payload: JSON.stringify({copyRequiresWriterPermission: true}), // or payload: JSON.stringify({labels: {restricted: true}})
headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
}
References:
Files of Drive API v2
Files of Drive API v3
Files: update of Drive API v3
If I misunderstood your question and this was not the direction you want, I apologize.
Related
I have the following code that I would like to use Drive v3 in App Script
function myFunction() {
let id = "<YOUR ODS FILE ID>";
let file = DriveApp.getFileById(id);
let fileBlob = file.getBlob();
newFile = {
name: "New File",
mimeType: "application/vnd.google-apps.spreadsheet"
}
try{
Drive.Files.create(newFile, fileBlob);
}catch(e){
Logger.log("Error");
Logger.log(e);
}
}
However by default the google app script only makes v2 available. The documentation does not seem so easy to do this migration directly in App Script.
How can I use Drive v3 in this code directly in the google app script?
I believe your goal as follows.
You want to convert the file of let file = DriveApp.getFileById(id) (ODS file from let id = "<YOUR ODS FILE ID>") as Google Spreadsheet.
You want to achieve this using Drive API v3 with UrlFetchApp of Google Apps Script.
Modification points:
Although, unfortunately, I'm not sure about the file size of let file = DriveApp.getFileById(id) from your question, I think that in your situation, the file content is required to be sent as multipart/form-data. Ref
At Advanced Google services, this multipart/form-data is achieved at the internal server side. But, when you want to achieve this using UrlFetchApp, it is required to create the request body.
When above points are reflected to the sample script, it becomes as follows.
Sample script:
In this case, Drive API is used. So please enable Drive API at Advanced Google services.
function myFunction() {
const fileId = "<YOUR ODS FILE ID>"; // Please set the file ID.
const metadata = {
name: "New File",
mimeType: MimeType.GOOGLE_SHEETS,
// parents: ["### folder ID ###"], // If you want to put the converted Spreadsheet to the specific folder, please use this.
};
const payload = {
metadata: Utilities.newBlob(JSON.stringify(metadata), "application/json"),
file: DriveApp.getFileById(fileId).getBlob(),
};
const options = {
method: "post",
payload: payload,
headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
};
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart"
const res = UrlFetchApp.fetch(url, options).getContentText();
console.log(res);
// DriveApp.createFile(blob) // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive".
}
Note:
At uploadType=multipart method, the official document says as follows.
Use this upload type to quickly transfer a small file (5 MB or less) and metadata that describes the file, in a single request.
When you want to use the file more than 5 MB for this, please use the resumable upload. Ref
By the way, in your script, it seems that the ODF file on your Google Drive is used. In this case, you can also achieve your goal using the method of "Files: copy" in Drive API v3. The sample script is as follows.
function myFunction2() {
const fileId = "<YOUR ODS FILE ID>"; // Please set the file ID.
const url = `https://www.googleapis.com/drive/v3/files/${fileId}/copy`;
const params = {
method: "post",
headers: {authorization: `Bearer ${ScriptApp.getOAuthToken()}`},
contentType: "application/json",
payload: JSON.stringify({name: "New name", mimeType: MimeType.GOOGLE_SHEETS})
};
const res = UrlFetchApp.fetch(url, params);
console.log(res.getContentText())
}
References:
Files: create
Upload file data
fetch(url, params)
Files: copy
Trying to explore this with a very simple script but I'm getting an insufficient permissions error:
function mini(){
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var options = {
method: "GET",
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
},
}
var url = "https://www.googleapis.com/drive/v2/files/"+gdriveId+"/children";
var response = JSON.parse(UrlFetchApp.fetch( url, options).getContentText());
}
I tried enabling the v2 drive api in the advanced google services dropdown but that didn't work.
I believe your situation and goal as follows.
From gdriveId in your script, I thought that you want to retrieve the folder list in the root folder of gdriveId using the method of "Children: list" in Drive API v2.
You have already enabled Drive API at Advanced Google Services.
For this, how about this answer?
Modification points:
When your script is put to new GAS project and Drive API is enabled at Advanced Google Services, the scopes of the project is only https://www.googleapis.com/auth/script.external_request. The required scope can be automatically detected by the script editor. But, even when Drive API is only enabled, it seems that no scopes are added. I think that the reason of your issue is this.
Under above situation, if you want to retrieve the access token including the required scopes, in order to make the script editor automatically detect the scope of https://www.googleapis.com/auth/drive.readonly, for example, please put // DriveApp.getFiles() to the script as a comment line.
In this case, when you use the methods for other scopes in your script, those scopes can be automatically detected and added by the script editor.
Modified script 1:
When your script is modified, it becomes as follows.
function mini(){
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var options = {
method: "GET",
headers: {
'Authorization': 'Bearer ' + ScriptApp.getOAuthToken()
},
}
var url = "https://www.googleapis.com/drive/v2/files/"+gdriveId+"/children";
var response = JSON.parse(UrlFetchApp.fetch( url, options).getContentText());
}
// DriveApp.getFiles() // <--- Added this comment line. By this, the scope of https://www.googleapis.com/auth/drive.readonly is added.
Modified script 2:
When the method of Advanced Google service is used, the scope of https://www.googleapis.com/auth/drive is automatically added. By this, the following script works.
function test() {
var gdriveId = "1hp8ncIG4Ww7FH8wi7HjJzzzzzzz";
var res = Drive.Children.list(gdriveId);
console.log(res)
}
Other pattern:
From June 1, 2020, the files and folders in the shared Drive can be retrieved by Drive service. So you can also use the following script.
function myFunction() {
const getFolderList = (id, folders = []) => {
const f = DriveApp.getFolderById(id);
const fols = f.getFolders();
let temp = [];
while (fols.hasNext()) {
const fol = fols.next();
temp.push({name: fol.getName(), id: fol.getId(), parent: f.getName()});
}
if (temp.length > 0) {
folders.push(temp);
temp.forEach((e) => getFolderList(e.id, folders));
}
return folders.flat();
};
var gdriveId = "###"; // Please set the Drive ID.
const res = getFolderList(gdriveId);
console.log(res);
}
References:
Advanced Google services
Children: list of Drive API v2
Authorization Scopes
If you want to give permission to write with ScriptApp.getOAuthToken(), just add the following code in a commented out form and authorize it at runtime. If you don't do this, you'll only be able to download and browse.
//DriveApp.addFile("test");
Reference URL:https://00m.in/UeeOB
I've been bashing my head at this for over a day, but I can't figure out how to upload data to Google Cloud Storage via an app script attached to a google sheet. I've been running into issues with authorisation. I've copied the getService method from here (pasted below) but the service keeps failing to receive authorisation. service.hasAccess() always returns false.
function uploadFileToGCS(dataJSON) {
var service = getService();
if (!service.hasAccess()) {
Browser.msgBox("Failed to grant service access")
return;
}
var url = 'https://www.googleapis.com/upload/storage/v1/b/BUCKET/o?uploadType=media&name=FILE'
.replace("BUCKET", params.BUCKET_NAME)
.replace("FILE", encodeURIComponent(params.FILE_PATH));
var response = UrlFetchApp.fetch(url, {
method: "POST",
payload: dataJSON,
contentType: "application/json",
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
}
function getService() {
return OAuth2.createService('ctrlq')
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setClientId(params.CLIENT_ID)
.setClientSecret(params.CLIENT_SECRET)
.setCallbackFunction('authCallback')
.setPropertyStore(PropertiesService.getUserProperties())
.setScope('https://www.googleapis.com/auth/devstorage.read_write')
.setParam('access_type', 'offline')
.setParam('approval_prompt', 'force')
.setParam('login_hint', Session.getActiveUser().getEmail());
}
function authCallback(request) {
var service = getService();
var authorized = service.handleCallback(request);
if (authorized) {
return HtmlService.createHtmlOutput('Connected to Google Cloud Storage');
} else {
return HtmlService.createHtmlOutput('Access Denied');
}
}
I've created OAUTH credentials for a web-app on the Google Cloud Console. I've also enabled the Cloud Storage API and Google Cloud Storage JSON API. I'm unsure however on the redirect URL. (Ideally, I'd like to use a service account because I just want to take the values from the spreadsheet and upload them as a JSON file.)
Anyway, appreciate the help!
I think google app script project and google cloud project should be linked. You need to create a google cloud project to use this API.
I encountered a similar problem when I wanted to duplicate an object in Cloud Storage. Not sure if this is the solution for you, but I'm putting it here in case someone need it.
Just use the XML-formmatted REST API with OAuth2 token, and the code looks like this:
var objectSource = "SOURCE_BUCKET_NAME/SOURCE_OBJECT_NAME";
var url = "https://storage.googleapis.com/DESTINATION_BUCKET_NAME/NAME_OF_COPY";
var resp = UrlFetchApp.fetch(url, {
method: "PUT",
headers: {
Authorization: 'Bearer '+ OAUTH2_TOKEN,
"x-goog-copy-source": objectSource,
},
'muteHttpExceptions': true,
});
Check out the Cloud Storage's document for differences between copy and upload.
I can't find a way to change modification date on a file on Google Drive using Google Apps Script.
After I do a file.makeCopy(newFile, newFolder), I would like to make the modification time on the new copy the same as the original file.
I can't find documented way to do this...
You want to modify the modified time of the file on Google Drive.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
In this answer, I used the method of Files: update in Drive API v3.
Sample script:
Before you use this script, please set the variables of newModifiedTime and fileId.
function myFunction() {
var newModifiedTime = "2019-01-01T00:00:00.000Z"; // Please set the new modified time.
var fileId = "###"; // Please set the file ID you want to modify the modified time.
var url = "https://www.googleapis.com/drive/v3/files/" + fileId;
var params = {
method: "patch",
headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()},
payload: JSON.stringify({modifiedTime: newModifiedTime}),
contentType: "application/json",
};
UrlFetchApp.fetch(url, params);
// DriveApp.createFile(blob);
}
Note:
The last line of // DriveApp.createFile(blob); is used for automatically adding the scope of https://www.googleapis.com/auth/drive and enabling Drive API.
In this case, please use the date string of RFC 3339 date-time. It's like 2019-01-01T00:00:00.000Z.
Although I tested this for Drive API v2, it seems that Drive API v2 cannot modify the modified date of the file.
References:
Files: update(Drive API v3)
Class UrlFetchApp
If I misunderstood your question and this was not the result you want, I apologize.
There is a way to modify the modifiedTime with the advanced Drive service (don't forget to turn it on in the project settings).
function setModifiedDate(originalFile /* DriveApp.File */, copyFile /* DriveApp.File */) {
/* based on the Drive API v2 */
Drive.Files.patch({
modifiedDate: originalFile.getLastUpdated().toISOString()
}, copyFile.getId(), {
setModifiedDate: true
})
}
This changes the lastUpdated() date and the Last Modified date on the Drive. The file I'm using is just an ascii text file.
function modifyFile() {
var file=DriveApp.getFileById("fileId");
Logger.log(file.getLastUpdated());
var content=file.getBlob().getDataAsString();
content+='\nThis is a new line';
file.setContent(content);
Logger.log(file.getLastUpdated());
}
This changes the Last Modified Date of a Google Doc
function modifyADocFile() {
var file=DriveApp.getFileById("Document Id");
var doc=DocumentApp.openById(file.getId());
var body=doc.getBody();
var bodytext=body.getText();
bodytext+='\nThis is a new line';
body.setText(bodytext);
doc.saveAndClose();
}
I am moving file this way:
var idOriginFolder = 'ABCDEFG12345abcdefg';
var originFolder = DriveApp.getFolderById(idOriginFolder);
var destinationFolder = DriveApp.createFolder('New Folder');
var searchString = '"'+idOriginFolder+'" in parents'
var foundFiles = DriveApp.searchFiles(searchString);
while (foundFiles.hasNext()){
var file = foundFiles.next();
destinationFolder.addFile(file);
originFolder.removeFile(file);
}
The files are moved correctly, but the modification date of every one moved file is changed to script execution date. Do you know any way to avoid this? When I move files throught of the Web Interface of Google Drive this not happen.
In my experience, the modification date of files is not changed by moving using Drive API v3. In your question, when the files were moved using DriveApp, the modification date was changed. I think that DriveApp uses Drive API v2. So I investigated this, because I was interested in this situation.
For Drive API v2
It was found that when the files were moved using drive.files.update and drive.files.patch, the modification date was changed.
For Drive API v3
It was found that when the files were moved using drive.files.update, the modification date was NOT changed.
Sample script :
The sample script for using Drive API v3 is as follows.
var idOriginFolder = 'ABCDEFG12345abcdefg';
var destinationFolder = DriveApp.createFolder('New Folder').getId();
var searchString = '"'+idOriginFolder+'" in parents'
var foundFiles = DriveApp.searchFiles(searchString);
var requests = [];
while (foundFiles.hasNext()){
var file = foundFiles.next();
requests.push({
url: "https://www.googleapis.com/drive/v3/files/" + file.getId() + "?addParents=" + destinationFolder + "&removeParents=" + idOriginFolder,
method: "patch",
headers: {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
muteHttpExceptions: true,
});
}
var res = UrlFetchApp.fetchAll(requests);
Logger.log(res)
Note :
From these results, it is considered that moving files by Web Interface may be due to Drive API v3.
This is a simple sample script. So if you want to move a lot of files, I recommend to use the Batching Requests.
Reference :
Files: update for Drive API v2
Files: patch for Drive API v2
Files: update for Drive API v3
Batching Requests
If this was not useful for you, I'm sorry.