ScriptApp.getOAuthToken not getting the right permissions for drive through url fetch app? - google-apps-script

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

Related

How to use Drive v3 in google app script?

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

Calling Google Apps Script in another Project File

I am trying to call a Google Apps Script file that is in another project file following the sample here using UrlFetchApp.fetch.
I'm getting the same error that the original poster mentions but I am not having an success with my sample.
Did Google change something in the last 4 years that prevents me from calling the other script file?
See script below.
Below is the function that I am using to call the other project file
function makeRequest()
{
var webAppUrl = "https://script.google.com/macros/s/***/exec";
var auth = ScriptApp.getOAuthToken();
var header = { 'Authorization': 'Bearer ' + auth };
var options = { 'method':'post', 'headers':header };
var resp = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(resp);
}
Below is the function that I am trying to call. Additionally, I have ran the authorizeDrive function and published as a webapp.
function authorizeDrive()
{
var forScope = DriveApp.getRootFolder();
}
function doPost()
{
var ss = SpreadsheetApp.openById('ssID');
var name = ss.getName();
Logger.log('called');
return ContentService.createTextOutput(name);
}
You want to run the Google Apps Script in the GAS project A by accessing to Web Apps from the GAS project B.
In your case, Web Apps is deployed by Who has access to the app: of Only myself or Anyone.
You want to access to Web Apps using the access token.
The GAS project A and B are in your Google Drive.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
I think that in your case, the scope is required to be added to the project including makeRequest(). So in order to add the scope for accessing to Web Apps using the access token, how about the following modification?
Modified script:
function makeRequest()
{
var webAppUrl = "https://script.google.com/macros/s/***/exec";
var auth = ScriptApp.getOAuthToken();
var header = { 'Authorization': 'Bearer ' + auth };
var options = { 'method':'post', 'headers':header };
var resp = UrlFetchApp.fetch(webAppUrl, options);
Logger.log(resp);
}
// DriveApp.getFiles() // This comment line is used for automatically detecting the scope.
Please add the // DriveApp.getFiles() of the comment line. This comment line is used for automatically detecting the scope.
In this case, https://www.googleapis.com/auth/drive.readonly is added to the scopes. If this didn't resolve your issue, please add the comment line of // DriveApp.createFile(blob). In this case, https://www.googleapis.com/auth/drive is added.
Note:
When the script of Web Apps side is modified, please redeploy it as new version. By this, the latest script is reflected to Web Apps. Please be careful this.
If the owner of GAS project of Web Apps is not your account which has the script of makeRequest(), at first, please share the GAS project file of Web Apps with your account. Then, please test it. This specification has added at April 11, 2018. Also, please be careful this.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script
If I misunderstood your question and this was not the result you want, I apologize.

Set Google Drive file modification time from Google App Script

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();
}

Google Apps Script Wants Unrestricted Scope

Simple function here in Google Apps Script:
function driveSearch() {
// Log the name of every file in the user's Drive whose visibility is anyonewithLink or anyonecanfind
var files = DriveApp.searchFiles(
'visibility = "anyoneWithLink" or visibility = "anyoneCanFind"');
while (files.hasNext()) {
var file = files.next();
var owner = file.getOwner().getName();
var sa = file.getSharingAccess();
Logger.log(file.getName());
Logger.log('Owner:'+owner);
Logger.log("SharingAccess:"+sa);
}
}
It want to find shared files in my gsuite drive.
However, it says I don't have permissions to run DriveApp
My permissions are set and requested correctly, like so:
{
"timeZone": "America/New_York",
"dependencies": {
},
"exceptionLogging": "STACKDRIVER",
"oauthScopes": [
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/drive.metadata.readonly"
]
}
The error is
You do not have permission to call DriveApp.searchFiles. Required permissions: https://www.googleapis.com/auth/drive (line 3, file "Code")
Why does searchFiles require delete permissions? I am very worried about inadvertent deletion, I don't want the full scope. Is there something else I'm doing wrong?
Lastly, yes my Gsuite allows Google Apps Script.
How about this workaround? In this workaround, the endpoint of Drive API is directly requested by UrlFetchApp, and the following 2 scopes are used.
https://www.googleapis.com/auth/drive.metadata.readonly
This is used to the access token which is used for using Drive API.
https://www.googleapis.com/auth/script.external_request
This is used for using UrlFetchApp.
Enable Drive API at API console
Before you use this script, please enable Drive API as follows.
On script editor
Resources -> Cloud Platform project
View API console
At Getting started, click "Explore and enable APIs".
At left side, click Library.
At "Search for APIs & services", input "Drive". And click Drive API.
Click Enable button.
If API has already been enabled, please don't turn off.
Sample script:
function myFunction() {
var baseUrl = "https://www.googleapis.com/drive/v3/files";
var q = 'visibility = "anyoneWithLink" or visibility = "anyoneCanFind"';
var fields = "files(id,name,owners,permissions),nextPageToken";
var pageToken = "";
var results = [];
var params = {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}};
do {
var endpoint = baseUrl + "?pageSize=1000&q=" + encodeURIComponent(q) + "&fields=" + encodeURIComponent(fields) + "&pageToken=" + pageToken;
var res = UrlFetchApp.fetch(endpoint, params);
res = JSON.parse(res.getContentText());
Array.prototype.push.apply(results, res.files);
pageToken = res.nextPageToken || "";
} while (pageToken);
results.forEach(function(e) {
Logger.log(e.name);
Logger.log('Owner: ' + e.owners.map(function(f) {return f.displayName}).join(","));
Logger.log("SharingAccess: " + e.permissions.map(function(f) {return f.id}).join(","));
});
}
Note:
In this sample script, the log is the same with your script.
References:
Drive API
list
UrlFetchApp
If this was not the result you want, I apologize.

How to download a file using a url in Google Apps Script

I am fairly new to Google Apps Script. I am using Google's functionality to access the DFA/DCM Trafficking and Reporting API through App Scripts without having to use OAuth.
When I run the DCM Report to then convert into google sheets, I am not able to figure out how to use either urls i'm supplied with to download the CSV.
Here is the code i'm using.
var file = DCM.Reports.run(profile.profileId,30792432);
var file2 = DCM.Files.get(30792432, file.id);
//wait till running of the report is complete.
file2 = DCM.Files.get(30792432, file.id);
var response = UrlFetchApp.fetch(file2.urls.browserUrl);
I also try using:
file2.urls.apiUrl();
for the UrlFetchApp service, but that didn't work either.
Any help on how to execute the url to download the file as an object where I can paste into google sheets would be greatly appreciated.
Add the ScriptApp authorization bearer as a header in the parameters while using the apiurl call. Something like:
var token = ScriptApp.getOAuthToken();
var headersOptions = {
Authorization : 'Bearer ' + token
};
var options = {
headers : headersOptions
};
var csvDoc = UrlFetchApp.fetch(file2.url.apiurl, options);