我可以读取使用 Google Picker 和 drive.file oauth 范围打开的驱动器文件吗?
Can I read a drive file opened using Google Picker with drive.file oauth scope?
我创建了一个表单插件,范围为:
https://www.googleapis.com/auth/drive.file
并创建了一个选择器:
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;
}
使用此选择器打开文件后,我尝试在 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 失败并出现以下错误:
code: 404, message: "File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU"
我在服务器端(应用程序脚本)尝试了同样的方法,但得到了类似的错误:
DriveApp.getFolderById(文件 ID)
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)
与高级驱动相同api:
Drive.Files.get(文件 ID)
returns:
GoogleJsonResponseException: API call to drive.files.get failed with error: File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU
我是否需要 drive.readonly 范围来读取用户使用 Google 选择器打开的文件?
是的,因为 https://www.googleapis.com/auth/drive.file
范围只允许您:
View and manage Google Drive files and folders that you have opened or created with this app
和https://www.googleapis.com/auth/drive.readonly
:
See and download all your Google Drive files
您可以在此处查看 scopes 的完整列表。
我发现了问题。如果我从 pickerCallback:
移动这个 gapi.load 代码,它就会工作
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);
});
});
});
到javascript 加载:
function onGsiLoad()
{
return gapi.load('client', function () {
return gapi.client.load('drive', 'v2', function () {
gsiLoaded = true;
maybeEnablePicker();
});
});
}
并且在pickerCallback中只有gapi.client.drive.files.get:
var file = gapi.client.drive.files.get({ 'fileId': fileId });
file.execute(function (resp) {
showMessage(resp);
});
工作测试用例在这里:https://docs.google.com/forms/d/1h3FWKVpGbCApg1_2unD3L86QlOmh9CIwK-W1Q97UTYQ/edit?usp=sharing
越野车一号在这里:
https://docs.google.com/forms/d/1jpEa-mp8ccCZhEGlgBN52AML2i1oHIShFpY8Oe3GC44/edit?usp=sharing
我创建了一个表单插件,范围为:
https://www.googleapis.com/auth/drive.file
并创建了一个选择器:
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;
}
使用此选择器打开文件后,我尝试在 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 失败并出现以下错误:
code: 404, message: "File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU"
我在服务器端(应用程序脚本)尝试了同样的方法,但得到了类似的错误:
DriveApp.getFolderById(文件 ID)
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)
与高级驱动相同api:
Drive.Files.get(文件 ID)
returns:
GoogleJsonResponseException: API call to drive.files.get failed with error: File not found: 1d0cqiT3aipgjMfLPolzgWVrnsl4xPxUJ1_7pH3ONVzU
我是否需要 drive.readonly 范围来读取用户使用 Google 选择器打开的文件?
是的,因为 https://www.googleapis.com/auth/drive.file
范围只允许您:
View and manage Google Drive files and folders that you have opened or created with this app
和https://www.googleapis.com/auth/drive.readonly
:
See and download all your Google Drive files
您可以在此处查看 scopes 的完整列表。
我发现了问题。如果我从 pickerCallback:
移动这个 gapi.load 代码,它就会工作 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);
});
});
});
到javascript 加载:
function onGsiLoad()
{
return gapi.load('client', function () {
return gapi.client.load('drive', 'v2', function () {
gsiLoaded = true;
maybeEnablePicker();
});
});
}
并且在pickerCallback中只有gapi.client.drive.files.get:
var file = gapi.client.drive.files.get({ 'fileId': fileId });
file.execute(function (resp) {
showMessage(resp);
});
工作测试用例在这里:https://docs.google.com/forms/d/1h3FWKVpGbCApg1_2unD3L86QlOmh9CIwK-W1Q97UTYQ/edit?usp=sharing
越野车一号在这里: https://docs.google.com/forms/d/1jpEa-mp8ccCZhEGlgBN52AML2i1oHIShFpY8Oe3GC44/edit?usp=sharing