【发布时间】:2019-09-11 09:47:54
【问题描述】:
我想将 GAS 中的 Google 文档(或任何其他文档)恢复到较早的版本。我设法访问了修订版,甚至下载了较旧的修订版,但是如何将文档恢复到指定的修订版?
【问题讨论】:
-
您能否分享一下您如何访问@WillemS 的修订版?
标签: google-apps-script google-drive-api
我想将 GAS 中的 Google 文档(或任何其他文档)恢复到较早的版本。我设法访问了修订版,甚至下载了较旧的修订版,但是如何将文档恢复到指定的修订版?
【问题讨论】:
标签: google-apps-script google-drive-api
如果我的理解是正确的,那么这个答案呢?
很遗憾,在现阶段,Google Docs 的修订无法直接通过 API 使用脚本进行更改。因此,作为几种解决方法之一,我想建议使用导出的数据覆盖 Google Docs 文件。此变通方法的流程如下。
通过此流程,Google Docs 文件将恢复到以前的版本。
作为重要的一点,当 Google Docs 文件导出为 Microsoft Docs 文件时,在大多数情况下,被覆盖的 Google Docs 文件不会从该版本的原始 Google Docs 更改。但我不确定这种解决方法是否适用于所有情况。所以请注意这一点。
此解决方法的示例脚本如下。在运行脚本之前,please enable Drive API at Advanced Google services。
function myFunction() {
var revisionId = "1"; // Please set the revision ID you want to revert.
var googleDocsFileId = "###"; // Please set the Google Docs file ID.
var endpoints = Drive.Revisions.get(googleDocsFileId, revisionId).exportLinks;
var keys = Object.keys(endpoints);
for (var i = 0; i < keys.length; i++) {
if (keys[i].indexOf("application/vnd.openxmlformats-officedocument") > -1) {
var endpoint = endpoints[keys[i]] + "&access_token=" + ScriptApp.getOAuthToken();
var mediaData = UrlFetchApp.fetch(endpoint).getBlob();
Logger.log(mediaData.getBytes().length)
Drive.Files.update({}, googleDocsFileId, mediaData);
break;
}
}
}
如果这不是您想要的方向,我深表歉意。
从 2020 年 1 月起,访问令牌不能与 access_token=### 等查询参数一起使用。 Ref 所以请使用请求头的访问令牌而不是查询参数。如下。
var res = UrlFetchApp.fetch(url, {headers: {Authorization: "Bearer " + ScriptApp.getOAuthToken()}});
【讨论】:
您可以按照these instructions 手动操作。此外,正如您在 revision resource documentation 中看到的那样,您可以更改 published 属性以将特定修订标记为“活动版本”。
要通过 Apps 脚本执行此操作,您需要 enable Google Advanced Services,这将允许您充分使用 API。然后您可以使用update 方法(Documentation here),使用所需修订的ID 并将其published 属性更改为true。
请记住,根据文档:
这仅适用于 Google 文档。
【讨论】:
这是在python 中使用google-api-python-client 包实现的一对示例函数。
首先,调用gsGetLatestRevisionId 获取最新版本作为还原点,然后再开始在应用中使用 Google 文档:
from dateutil import parser
def gsGetLatestRevisionId(gc:Resource,gsId:str) -> str:
'''
Gets the latest revisionId for a google docs file with id=gsId.
We can use this as a restore point after manipulating a google spreadsheet
:param gc: The authenticated Google drive api discovery.build service
:param gsId: The google sheets id for the file we want to analyse
:return: revisionId of the latest revision
'''
revisions = gc.revisions().list(fileId=gsId).execute()
revisionDateIds = {}
for rd in revisions['revisions']:
revisionDateIds[parser.parse(rd['modifiedTime'])] = rd['id']
latestDate = max(revisionDateIds.keys())
return revisionDateIds[latestDate]
一旦出现严重错误,请致电gsRevertToRevision 将电子表格恢复到之前确定的恢复点:
from io import BytesIO
from googleapiclient.http import MediaIoBaseUpload
def gsRevertToRevision(gc:Resource,gsId:str,revisionId:str) -> dict:
'''
Reverts the google docs file with id gsId to the revision identified by
revisionId.
We use this as a restore point pointer so we can revert a google spreadsheet.
:param gc: The authenticated Google drive api discovery.build service
:param gsId: the google sheets id for the file we want to revert
:param revisionId: The google sheet's revision id that we want to revert the file to
:raises [ValueError]: if unable to download the revision file from Google Drive API.
:return: result of the update to the restored revision
'''
# Get the name of the spreadsheet
name = ''.join(gc.files().get(fileId=gsId, fields='name').execute().values())
# Get the download links (exportLinks)
endPoints = gc.revisions().get(fileId=gsId, revisionId=revisionId,
fields='exportLinks').execute()
# Different classes of download links are supported, so we choose the one
# likely to give us the best outcome
mimeType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
endPoint = endPoints['exportLinks'][mimeType]
# We use the protected _http functionality in the Google service
# object to download this file with the correct headers in place.
# Hopefully they don't replace or remove the _http method in future
# revisions of the google api python library!
# The result is a tuple with response json information and the actual
# file data in the second object.
response, fileData = gc._http.request(endPoint)
if response.status == 200:
metaData = {
'name': name, 'mimeType': mimeType,
}
fh = BytesIO(fileData)
mediaBody = MediaIoBaseUpload(fh, mimetype=mimeType,
chunksize=1024*1024, resumable=True)
result = gc.files().update(
fileId=gsId,
body=metaData,
media_body=mediaBody
).execute()
else:
raise ValueError('Unable to download the revision file from google drive api.')
return result
这是为与 Google 电子表格一起使用而设计的,但也可以适用于其他文档类型。诀窍是为特定文档选择最实用的exportLink mime-type。我没有概括此功能,因为这更多是概念的演示。此外,转换可能会引入伪影,因此我希望人们不要在没有意识到这个潜在问题的情况下简单地复制和粘贴。
gsRevertToRevision 当然可以单独使用并提供任何有效的revisionId,因此这符合问题中提出的一般用例要求,至少就修订而言。
另一个“特性”是,与其他类似的解决方案不同,它不会创建文件来将下载的实例文件数据写入磁盘。相反,所有内容都保存在 RAM 中。如果您想要以这种方式处理大文件,请记住这一点,因为您最终可能会耗尽内存。
gsRevertToRevision 通过导出然后重新导入文档实例来工作。这涉及文档类型转换(两次),并可能导致数据和/或功能丢失。确保您的电子表格各个方面都使其重新投入测试。
【讨论】: