I created a forms addon with scope:
https://www.googleapis.com/auth/drive.file
and created a picker:
function onOpen(e)
{
FormApp.getUi().createAddonMenu()
.addItem('Sync to Drive', 'showPicker')
.addToUi();
}
function getOAuthToken() {
return ScriptApp.getOAuthToken();
}
function showPicker() {
var html = HtmlService.createHtmlOutputFromFile('Picker.html')
.setWidth(600)
.setHeight(425)
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
FormApp.getUi().showModalDialog(html, 'Select Folder');
}
// Use Advanced Drive Service - https://developers.google.com/apps-script/advanced/drive
function getFileWithAdvancedDriveService(fileId)
{
var drivefl = Drive.Files.get(fileId);
FormApp.getUi().alert('File: '+drivefl);
return drivefl;
}
// Use Drive Service - https://developers.google.com/apps-script/reference/drive
function getFileWithDriveService(fileId)
{
var drivefl = DriveApp.getFileById(fileId);
FormApp.getUi().alert('File: '+drivefl);
return drivefl;
}
After I open a file using this picker, I am trying to read it in the pickerCallback:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css" />
<script type="text/javascript">
var DIALOG_DIMENSIONS = {
width: 600,
height: 425,
};
var authToken;
var pickerApiLoaded = false;
function onApiLoad() {
gapi.load('picker', {
callback: function () {
pickerApiLoaded = true;
},
});
google.script.run.withSuccessHandler(createPicker).withFailureHandler(showError).getOAuthToken();
}
function createPicker(token) {
authToken = token;
if (pickerApiLoaded && authToken) {
var docsView = new google.picker.DocsView()
.setIncludeFolders(true);
var picker = new google.picker.PickerBuilder()
.addView(docsView)
.enableFeature(google.picker.Feature.NAV_HIDDEN)
.hideTitleBar()
.setOAuthToken(authToken)
.setCallback(pickerCallback)
.setOrigin('https://docs.google.com')
.build();
picker.setVisible(true);
} else {
showError('Unable to load the file picker.');
}
}
function pickerCallback(data, ctx) {
var action = data[google.picker.Response.ACTION];
if(action == google.picker.Action.PICKED) {
var doc = data[google.picker.Response.DOCUMENTS][0];
var id = doc[google.picker.Document.ID];
// Option 1 - Advanced Drive Service in apps script
return google.script.run.withSuccessHandler(showMessage).withFailureHandler(showError).getFileWithAdvancedDriveService(id);
// Option 2 - Drive Service in apps script
return google.script.run.withSuccessHandler(showMessage).withFailureHandler(showError).getFileWithDriveService(id);
// Option 3 - Drive Service in client
return gapi.load('client', function () {
gapi.client.load('drive', 'v2', function () {
gapi.client.setToken({ access_token: authToken });
var file = gapi.client.drive.files.get({ 'fileId': id });
file.execute(function (resp) {
showMessage(resp);
});
});
});
} else if(action == google.picker.Action.CANCEL) {
google.script.host.close();
}
}
function showMessage(message) {
document.getElementById('result').innerHTML = '<div>Message:</div> ' + JSON.stringify(message);
}
function showError(message) {
document.getElementById('result').innerHTML = `<div>Error:</div> <div style="color:red;">${message}</div>`;
}
</script>
</head>
<body>
<div>
<p id="result"></p>
</div>
<script type="text/javascript" src="https://apis.google.com/js/api.js?onload=onApiLoad"></script>
</body>
</html>
gapi.client.drive.files.get fails with the error:
code: 404, message: "File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU"
I tried the same on the server side (apps script) and got similar error:
DriveApp.getFolderById(fileId)
returns:
You do not have permission to call DriveApp.getFolderById. Required permissions: (https://www.googleapis.com/auth/drive.readonly || https://www.googleapis.com/auth/drive)
Same with advanced drive api:
Drive.Files.get(fileId)
returns:
GoogleJsonResponseException: API call to drive.files.get failed with error: File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU
Do I need drive.readonly scope to read the file opened by the user using Google Picker?
I found the problem. It works if I move this gapi.load code from pickerCallback:
return gapi.load('client', function () {
gapi.client.load('drive', 'v2', function () {
gapi.client.setToken({ access_token: authToken });
var file = gapi.client.drive.files.get({ 'fileId': id });
file.execute(function (resp) {
showMessage(resp);
});
});
});
to javascript onload:
function onGsiLoad()
{
return gapi.load('client', function () {
return gapi.client.load('drive', 'v2', function () {
gsiLoaded = true;
maybeEnablePicker();
});
});
}
And only have gapi.client.drive.files.get in pickerCallback:
var file = gapi.client.drive.files.get({ 'fileId': fileId });
file.execute(function (resp) {
showMessage(resp);
});
Working test case is here: https://docs.google.com/forms/d/1h3FWKVpGbCApg1_2unD3L86QlOmh9CIwK-W1Q97UTYQ/edit?usp=sharing
Buggy one is here: https://docs.google.com/forms/d/1jpEa-mp8ccCZhEGlgBN52AML2i1oHIShFpY8Oe3GC44/edit?usp=sharing