From 1794f87f99763745aea6c035888495b7bd173d40 Mon Sep 17 00:00:00 2001 From: antelle Date: Thu, 8 Apr 2021 21:47:57 +0200 Subject: [PATCH] fix #618: team drive support in Google Drive --- app/scripts/locales/base.json | 1 + app/scripts/storage/impl/storage-gdrive.js | 163 ++++++++++++++------- release-notes.md | 1 + 3 files changed, 110 insertions(+), 55 deletions(-) diff --git a/app/scripts/locales/base.json b/app/scripts/locales/base.json index d0a8c8af..526e8b4e 100644 --- a/app/scripts/locales/base.json +++ b/app/scripts/locales/base.json @@ -697,6 +697,7 @@ "dropboxLinkCustom": "Own Dropbox app", "gdriveSharedWithMe": "Shared with me", + "gdriveTeamDrives": "Team drives", "webdavSaveMethod": "Save method", "webdavSaveMove": "Upload a temporary file and move", diff --git a/app/scripts/storage/impl/storage-gdrive.js b/app/scripts/storage/impl/storage-gdrive.js index 7403ebc3..37f50cff 100644 --- a/app/scripts/storage/impl/storage-gdrive.js +++ b/app/scripts/storage/impl/storage-gdrive.js @@ -1,6 +1,7 @@ import { StorageBase } from 'storage/storage-base'; import { Locale } from 'util/locale'; import { Features } from 'util/features'; +import { UrlFormat } from 'util/formatting/url-format'; import { GDriveApps } from 'const/cloud-storage-apps'; const NewFileIdPrefix = 'NewFile:'; @@ -27,11 +28,9 @@ class StorageGDrive extends StorageBase { } this.logger.debug('Load', path); const ts = this.logger.ts(); - const url = - this._baseUrl + - '/files/{id}/revisions/{rev}?alt=media' - .replace('{id}', path) - .replace('{rev}', stat.rev); + const url = UrlFormat.makeUrl(`${this._baseUrl}/files/${path}/revisions/${stat.rev}`, { + 'alt': 'media' + }); this._xhr({ url, responseType: 'arraybuffer', @@ -57,7 +56,11 @@ class StorageGDrive extends StorageBase { } this.logger.debug('Stat', path); const ts = this.logger.ts(); - const url = this._baseUrl + '/files/{id}?fields=headRevisionId'.replace('{id}', path); + const url = UrlFormat.makeUrl(`${this._baseUrl}/files/${path}`, { + fields: 'headRevisionId', + includeItemsFromAllDrives: true, + supportsAllDrives: true + }); this._xhr({ url, responseType: 'json', @@ -95,9 +98,12 @@ class StorageGDrive extends StorageBase { let dataType; let dataIsMultipart = false; if (isNew) { - url = - this._baseUrlUpload + - '/files?uploadType=multipart&fields=id,headRevisionId'; + url = UrlFormat.makeUrl(`${this._baseUrlUpload}/files`, { + uploadType: 'multipart', + fields: 'id,headRevisionId', + includeItemsFromAllDrives: true, + supportsAllDrives: true + }); const fileName = path.replace(NewFileIdPrefix, '') + '.kdbx'; const boundary = 'b' + Date.now() + 'x' + Math.round(Math.random() * 1000000); data = [ @@ -123,9 +129,12 @@ class StorageGDrive extends StorageBase { dataType = 'multipart/related; boundary="' + boundary + '"'; dataIsMultipart = true; } else { - url = - this._baseUrlUpload + - '/files/{id}?uploadType=media&fields=headRevisionId'.replace('{id}', path); + url = UrlFormat.makeUrl(`${this._baseUrlUpload}/files/${path}`, { + uploadType: 'media', + fields: 'headRevisionId', + includeItemsFromAllDrives: true, + supportsAllDrives: true + }); } this._xhr({ url, @@ -160,59 +169,103 @@ class StorageGDrive extends StorageBase { return callback && callback(err); } this.logger.debug('List'); - let query = - dir === 'shared' - ? 'sharedWithMe=true' - : dir - ? `"${dir}" in parents` - : '"root" in parents'; - query += ' and trashed=false'; - const url = - this._baseUrl + - '/files?fields={fields}&q={q}&pageSize=1000' - .replace( - '{fields}', - encodeURIComponent('files(id,name,mimeType,headRevisionId)') - ) - .replace('{q}', encodeURIComponent(query)); + const ts = this.logger.ts(); - this._xhr({ - url, - responseType: 'json', - success: (response) => { - if (!response) { - this.logger.error('List error', this.logger.ts(ts)); - return callback && callback('list error'); - } - this.logger.debug('Listed', this.logger.ts(ts)); - const fileList = response.files.map((f) => ({ - name: f.name, - path: f.id, - rev: f.headRevisionId, - dir: f.mimeType === 'application/vnd.google-apps.folder' - })); - if (!dir) { - fileList.unshift({ - name: Locale.gdriveSharedWithMe, - path: 'shared', - rev: undefined, + + if (dir === 'drives') { + const urlParams = { + pageSize: 100 + }; + + const url = UrlFormat.makeUrl(`${this._baseUrl}/drives`, urlParams); + + this._xhr({ + url, + responseType: 'json', + success: (response) => { + if (!response) { + this.logger.error('Drive list error', this.logger.ts(ts)); + return callback?.('drive list error'); + } + this.logger.debug('Listed drives', this.logger.ts(ts)); + + const fileList = response.drives.map((d) => ({ + name: d.name, + path: d.id, dir: true - }); + })); + return callback?.(null, fileList); + }, + error: (err) => { + this.logger.error('Drive dist error', this.logger.ts(ts), err); + return callback?.(err); } - return callback && callback(null, fileList); - }, - error: (err) => { - this.logger.error('List error', this.logger.ts(ts), err); - return callback && callback(err); + }); + } else { + let query = 'trashed=false and '; + if (dir === 'shared') { + query += 'sharedWithMe=true'; + } else if (dir) { + query += `"${dir}" in parents`; + } else { + query += '"root" in parents'; } - }); + + const urlParams = { + fields: 'files(id,name,mimeType,headRevisionId)', + q: query, + pageSize: 1000, + includeItemsFromAllDrives: true, + supportsAllDrives: true + }; + + const url = UrlFormat.makeUrl(`${this._baseUrl}/files`, urlParams); + + this._xhr({ + url, + responseType: 'json', + success: (response) => { + if (!response) { + this.logger.error('List error', this.logger.ts(ts)); + return callback?.('list error'); + } + this.logger.debug('Listed', this.logger.ts(ts)); + + const fileList = response.files.map((f) => ({ + name: f.name, + path: f.id, + rev: f.headRevisionId, + dir: f.mimeType === 'application/vnd.google-apps.folder' + })); + if (!dir) { + fileList.unshift({ + name: Locale.gdriveSharedWithMe, + path: 'shared', + rev: undefined, + dir: true + }); + fileList.unshift({ + name: Locale.gdriveTeamDrives, + path: 'drives', + rev: undefined, + dir: true + }); + } + return callback?.(null, fileList); + }, + error: (err) => { + this.logger.error('List error', this.logger.ts(ts), err); + return callback?.(err); + } + }); + } }); } remove(path, callback) { this.logger.debug('Remove', path); const ts = this.logger.ts(); - const url = this._baseUrl + '/files/{id}'.replace('{id}', path); + const url = `${this._baseUrl}/files/${path}`; this._xhr({ url, method: 'DELETE', diff --git a/release-notes.md b/release-notes.md index 50373bd0..a6d071cc 100644 --- a/release-notes.md +++ b/release-notes.md @@ -2,6 +2,7 @@ Release notes ------------- ##### v1.18.0 (TBD) `+` optimized memory consumption for large files +`+` team drives support in Google Drive `+` option to use short-lived tokens in cloud storages `+` opening XML and CSV files using the Open button `*` password generator now includes all selected character ranges