@pipedream/google_drive 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/actions/add-file-sharing-preference/add-file-sharing-preference.mjs +83 -0
- package/actions/copy-file/copy-file.mjs +34 -0
- package/actions/create-file/create-file.mjs +242 -0
- package/actions/create-file-from-template/create-file-from-template.mjs +98 -0
- package/actions/create-file-from-text/create-file-from-text.mjs +67 -0
- package/actions/create-folder/create-folder.mjs +54 -0
- package/actions/create-shared-drive/create-shared-drive.mjs +25 -0
- package/actions/delete-file/delete-file.mjs +37 -0
- package/actions/delete-shared-drive/delete-shared-drive.mjs +30 -0
- package/actions/download-file/download-file.mjs +120 -0
- package/actions/find-file/find-file.mjs +35 -0
- package/actions/find-folder/find-folder.mjs +38 -0
- package/actions/get-folder-id-for-path/get-folder-id-for-path.mjs +62 -0
- package/actions/get-shared-drive/get-shared-drive.mjs +37 -0
- package/actions/google-mime-types.mjs +19 -0
- package/actions/google-workspace-export-formats.mjs +74 -0
- package/actions/language-codes.mjs +742 -0
- package/actions/move-file/move-file.mjs +52 -0
- package/actions/move-file-to-trash/move-file-to-trash.mjs +41 -0
- package/actions/replace-file/replace-file.mjs +90 -0
- package/actions/search-shared-drives/search-shared-drives.mjs +34 -0
- package/actions/update-file/update-file.mjs +164 -0
- package/actions/update-shared-drive/update-shared-drive.mjs +77 -0
- package/actions/upload-file/upload-file.mjs +89 -0
- package/constants.mjs +190 -0
- package/google_drive.app.mjs +1429 -0
- package/package.json +23 -20
- package/pnpm-lock.yaml +393 -0
- package/sources/changes-to-specific-files/changes-to-specific-files.mjs +226 -0
- package/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs +110 -0
- package/sources/common-webhook.mjs +201 -0
- package/sources/new-files-instant/new-files-instant.mjs +95 -0
- package/sources/new-or-modified-comments/new-or-modified-comments.mjs +104 -0
- package/sources/new-or-modified-files/new-or-modified-files.mjs +66 -0
- package/sources/new-or-modified-folders/new-or-modified-folders.mjs +86 -0
- package/sources/new-shared-drive/new-shared-drive.mjs +68 -0
- package/utils.mjs +247 -0
- package/LICENSE +0 -7
- package/google_drive.app.js +0 -212
- package/sources/changes-to-specific-files/changes-to-specific-files.js +0 -226
- package/sources/new-or-modified-files/new-or-modified-files.js +0 -213
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import googleDrive from "../../google_drive.app.mjs";
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
key: "google_drive-new-shared-drive",
|
|
5
|
+
name: "New Shared Drive",
|
|
6
|
+
description: "Emits a new event any time a shared drive is created.",
|
|
7
|
+
version: "0.0.9",
|
|
8
|
+
type: "source",
|
|
9
|
+
dedupe: "unique",
|
|
10
|
+
props: {
|
|
11
|
+
googleDrive,
|
|
12
|
+
db: "$.service.db",
|
|
13
|
+
timer: {
|
|
14
|
+
label: "Polling interval",
|
|
15
|
+
description: "Interval to poll the Google Drive API for new shared drives",
|
|
16
|
+
type: "$.interface.timer",
|
|
17
|
+
default: {
|
|
18
|
+
intervalSeconds: 60 * 15, // 30 minutes
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
hooks: {
|
|
23
|
+
async deploy() {
|
|
24
|
+
const { drives: initDrives } = await this.googleDrive.listDrivesInPage();
|
|
25
|
+
for (const drive of initDrives) {
|
|
26
|
+
const newDrive = await this.googleDrive.getDrive(drive.id);
|
|
27
|
+
const meta = this.generateMeta(newDrive);
|
|
28
|
+
this.$emit(newDrive, meta);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this._setKnownDrives(initDrives.map((drive) => drive.id));
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
methods: {
|
|
35
|
+
_getKnownDrives() {
|
|
36
|
+
return this.db.get("driveIds");
|
|
37
|
+
},
|
|
38
|
+
_setKnownDrives(driveIds) {
|
|
39
|
+
this.db.set("driveIds", Array.from(driveIds));
|
|
40
|
+
},
|
|
41
|
+
generateMeta(drive) {
|
|
42
|
+
const ts = new Date(drive.createdTime).getTime();
|
|
43
|
+
return {
|
|
44
|
+
id: drive.id,
|
|
45
|
+
summary: drive.name,
|
|
46
|
+
ts,
|
|
47
|
+
};
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
async run() {
|
|
51
|
+
const knownDrives = new Set(this._getKnownDrives());
|
|
52
|
+
const drivesStream = this.googleDrive.listDrives();
|
|
53
|
+
for await (const drive of drivesStream) {
|
|
54
|
+
if (knownDrives.has(drive.id)) {
|
|
55
|
+
// We've already seen this drive, so we skip it
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
knownDrives.add(drive.id);
|
|
60
|
+
|
|
61
|
+
const newDrive = await this.googleDrive.getDrive(drive.id);
|
|
62
|
+
const meta = this.generateMeta(newDrive);
|
|
63
|
+
this.$emit(newDrive, meta);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this._setKnownDrives(knownDrives);
|
|
67
|
+
},
|
|
68
|
+
};
|
package/utils.mjs
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { axios } from "@pipedream/platform";
|
|
3
|
+
import {
|
|
4
|
+
MY_DRIVE_VALUE,
|
|
5
|
+
LEGACY_MY_DRIVE_VALUE,
|
|
6
|
+
MAX_FILE_OPTION_PATH_SEGMENTS,
|
|
7
|
+
} from "./constants.mjs";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns whether the specified drive ID corresponds to the authenticated
|
|
11
|
+
* user's My Drive or not
|
|
12
|
+
*
|
|
13
|
+
* @param {String} drive the ID value of a Google Drive
|
|
14
|
+
* @returns `true` only when the specified drive is the user's 'My Drive'
|
|
15
|
+
*/
|
|
16
|
+
function isMyDrive(drive) {
|
|
17
|
+
return drive === MY_DRIVE_VALUE || drive === LEGACY_MY_DRIVE_VALUE;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns a valid Google Drive ID to be used in Google Drive API calls
|
|
22
|
+
*
|
|
23
|
+
* @param {String} drive the ID value of a Google Drive, as provided by the
|
|
24
|
+
* `drive` prop definition of this app
|
|
25
|
+
* @returns the proper Google Drive ID to be used in Google Drive API calls
|
|
26
|
+
*/
|
|
27
|
+
function getDriveId(drive) {
|
|
28
|
+
return isMyDrive(drive)
|
|
29
|
+
? null
|
|
30
|
+
: drive;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Gets an options object to be used in functions that use the
|
|
35
|
+
* [the `drive.drives.list` API](https://bit.ly/3AiWE1x).
|
|
36
|
+
*
|
|
37
|
+
* @param {String} drive the ID value of a Google Drive, as provided by the
|
|
38
|
+
* `drive` prop definition of this app
|
|
39
|
+
* @param {object} [baseOpts = {}] - an object containing extra/optional
|
|
40
|
+
* parameters to be fed to the GDrive API call, as defined in [the API
|
|
41
|
+
* docs](https://bit.ly/3AnQDR1)
|
|
42
|
+
*
|
|
43
|
+
* @returns an object containing the options
|
|
44
|
+
*/
|
|
45
|
+
function getListFilesOpts(drive, baseOpts = {}) {
|
|
46
|
+
// Use default options (e.g., `corpora=drive`) for `files.list` if `drive` is
|
|
47
|
+
// empty or is "My Drive". Otherwise, use the "drive" corpus and include
|
|
48
|
+
// `supportsAllDrives` param.
|
|
49
|
+
const opts = (!drive || isMyDrive(drive))
|
|
50
|
+
? baseOpts
|
|
51
|
+
: {
|
|
52
|
+
...baseOpts,
|
|
53
|
+
corpora: "drive",
|
|
54
|
+
driveId: getDriveId(drive),
|
|
55
|
+
includeItemsFromAllDrives: true,
|
|
56
|
+
supportsAllDrives: true,
|
|
57
|
+
};
|
|
58
|
+
return opts;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns a file stream from a file URL or file path to be used in Google Drive
|
|
63
|
+
* API calls
|
|
64
|
+
*
|
|
65
|
+
* @param {Object} opts - an object containing options for getting a file stream
|
|
66
|
+
* @param {String} opts.fileUrl - the url of a file to download to a Readable
|
|
67
|
+
* stream
|
|
68
|
+
* @param {String} opts.filePath - the path to a file from which to create a
|
|
69
|
+
* Readable stream
|
|
70
|
+
* @returns {stream.Readable} a Readable stream from the file URL or file path
|
|
71
|
+
*/
|
|
72
|
+
async function getFileStream({
|
|
73
|
+
$, fileUrl, filePath,
|
|
74
|
+
}) {
|
|
75
|
+
return fileUrl
|
|
76
|
+
? (await axios($ ?? this, {
|
|
77
|
+
url: fileUrl,
|
|
78
|
+
method: "GET",
|
|
79
|
+
responseType: "stream",
|
|
80
|
+
}))
|
|
81
|
+
: fs.createReadStream(filePath);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Truncate an array of path segments from its base
|
|
86
|
+
*
|
|
87
|
+
* @param {String[]} pathArr - the array of path segments
|
|
88
|
+
* @returns the truncated array whose first element is "..." if truncated
|
|
89
|
+
*/
|
|
90
|
+
function truncatePath(pathArr) {
|
|
91
|
+
if (pathArr.length <= MAX_FILE_OPTION_PATH_SEGMENTS) {
|
|
92
|
+
return pathArr;
|
|
93
|
+
}
|
|
94
|
+
return [
|
|
95
|
+
"...",
|
|
96
|
+
...pathArr.slice(-1 * (MAX_FILE_OPTION_PATH_SEGMENTS - 1)),
|
|
97
|
+
];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Builds an object mapping file IDs to arrays of file/folder ID path segments from the drive's root
|
|
102
|
+
* folder to each file, using the `file.parents` property and a list of folders in the drive
|
|
103
|
+
*
|
|
104
|
+
* @see
|
|
105
|
+
* {@link https://developers.google.com/drive/api/v3/reference/files Google Drive File Resource}
|
|
106
|
+
*
|
|
107
|
+
* @param {object[]} files - the array of files for which to build paths
|
|
108
|
+
* @param {object[]} folders - the array of folders in the drive
|
|
109
|
+
* @returns {Object.<string, string[]>} the object mapping file IDs to arrays of path segments
|
|
110
|
+
*/
|
|
111
|
+
function buildFilePaths(files = [], folders = []) {
|
|
112
|
+
const folderIdToFolder = folders.reduce((acc, cur) => {
|
|
113
|
+
acc[cur.id] = cur;
|
|
114
|
+
return acc;
|
|
115
|
+
}, {});
|
|
116
|
+
const paths = {};
|
|
117
|
+
// Recursive function that returns an array of file `id`s representing the path to a file if
|
|
118
|
+
// requisite parent folders are available (in `file.parents`) to the requesting user, or an array
|
|
119
|
+
// containing the file ID otherwise
|
|
120
|
+
const pathToFile = (file) => {
|
|
121
|
+
if (!file) {
|
|
122
|
+
// unretrieved folder or root folder
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
if (paths[file.id] !== undefined) {
|
|
126
|
+
return paths[file.id];
|
|
127
|
+
}
|
|
128
|
+
if (!file.parents) {
|
|
129
|
+
// file belongs to a different drive and user does not have access to the parent
|
|
130
|
+
return [
|
|
131
|
+
file.id,
|
|
132
|
+
];
|
|
133
|
+
}
|
|
134
|
+
let parentPath;
|
|
135
|
+
for (const parent of file.parents) {
|
|
136
|
+
parentPath = pathToFile(folderIdToFolder[parent]);
|
|
137
|
+
paths[parent] = parentPath;
|
|
138
|
+
if (parentPath?.[0]) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return [
|
|
143
|
+
...parentPath,
|
|
144
|
+
file.id,
|
|
145
|
+
];
|
|
146
|
+
};
|
|
147
|
+
files.forEach((file) => {
|
|
148
|
+
paths[file.id] = pathToFile(file);
|
|
149
|
+
});
|
|
150
|
+
return paths;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Builds an object mapping file IDs to arrays of file/folder name path segments from the drive's
|
|
155
|
+
* root folder to each file, using the `file.parents` property and a list of folders in the drive
|
|
156
|
+
*
|
|
157
|
+
* @param {object[]} files - the array of files for which to build paths
|
|
158
|
+
* @param {object[]} folders - the array of folders in the drive
|
|
159
|
+
* @returns {Object.<string, string[]>} the object mapping file IDs to arrays of path segments
|
|
160
|
+
*/
|
|
161
|
+
function buildFileNamePaths(files = [], folders = []) {
|
|
162
|
+
const fileIdToFile = files.concat(folders).reduce((acc, cur) => {
|
|
163
|
+
acc[cur.id] = cur;
|
|
164
|
+
return acc;
|
|
165
|
+
}, {});
|
|
166
|
+
const fileIdToPath = buildFilePaths(files, folders);
|
|
167
|
+
return Object.fromEntries(Object.entries(fileIdToPath).map(([
|
|
168
|
+
id,
|
|
169
|
+
path,
|
|
170
|
+
]) => ([
|
|
171
|
+
id,
|
|
172
|
+
path.filter((id) => fileIdToFile[id]?.name)
|
|
173
|
+
.map((id) => fileIdToFile[id]?.name),
|
|
174
|
+
])));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Gets an object mapping file IDs to string paths from the drive's root folder to each file, if the
|
|
179
|
+
* file's `parents` are available to the requesting user
|
|
180
|
+
*
|
|
181
|
+
* @param {object[]} files - the array of files for which to get file paths
|
|
182
|
+
* @param {object[]} folders - the array of folders in the drive
|
|
183
|
+
* @returns {Object.<string, string>} the object mapping file IDs to file paths
|
|
184
|
+
*/
|
|
185
|
+
function getFilePaths(files = [], folders = []) {
|
|
186
|
+
const fileIdToNamePath = buildFileNamePaths(files, folders);
|
|
187
|
+
return Object.fromEntries(Object.entries(fileIdToNamePath).map(([
|
|
188
|
+
id,
|
|
189
|
+
path,
|
|
190
|
+
]) => ([
|
|
191
|
+
id,
|
|
192
|
+
truncatePath(path).join(" > "),
|
|
193
|
+
])));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Return an object compose of non-empty string valued properties of `obj`
|
|
198
|
+
*
|
|
199
|
+
* @param {Object} obj - the source object
|
|
200
|
+
* @param {String[]} [fromKeys] - keys of properties in `obj` to omit if corresponding value is
|
|
201
|
+
* empty string, or all keys by default
|
|
202
|
+
* @returns the new object
|
|
203
|
+
*/
|
|
204
|
+
function omitEmptyStringValues(obj, fromKeys) {
|
|
205
|
+
return Object.fromEntries(
|
|
206
|
+
// eslint-disable-next-line multiline-ternary,array-element-newline,array-bracket-newline
|
|
207
|
+
Object.entries(obj).filter(([ k, v ]) => {
|
|
208
|
+
return (fromKeys && !fromKeys.includes(k)) || v !== "";
|
|
209
|
+
}),
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* A utility function that accepts a string as an argument and reformats it in
|
|
215
|
+
* order to remove newline characters and consecutive spaces. Useful when
|
|
216
|
+
* dealing with very long templated strings that are split into multiple lines.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* // returns "This is a much cleaner string"
|
|
220
|
+
* toSingleLineString(`
|
|
221
|
+
* This is a much
|
|
222
|
+
* cleaner string
|
|
223
|
+
* `);
|
|
224
|
+
*
|
|
225
|
+
* @param {string} multiLineString the input string to reformat
|
|
226
|
+
* @returns a formatted string based on the content of the input argument,
|
|
227
|
+
* without newlines and multiple spaces
|
|
228
|
+
* Source: {@linkcode ../aws/sources/common/utils.mjs utils.mjs}.
|
|
229
|
+
*/
|
|
230
|
+
function toSingleLineString(multiLineString) {
|
|
231
|
+
return multiLineString
|
|
232
|
+
.trim()
|
|
233
|
+
.replace(/\n/g, " ")
|
|
234
|
+
.replace(/\s{2,}/g, " ");
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export {
|
|
238
|
+
MY_DRIVE_VALUE,
|
|
239
|
+
isMyDrive,
|
|
240
|
+
getDriveId,
|
|
241
|
+
getListFilesOpts,
|
|
242
|
+
getFileStream,
|
|
243
|
+
omitEmptyStringValues,
|
|
244
|
+
toSingleLineString,
|
|
245
|
+
buildFilePaths,
|
|
246
|
+
getFilePaths,
|
|
247
|
+
};
|
package/LICENSE
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
Copyright 2020 Pipedream, Inc.
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
|
-
|
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/google_drive.app.js
DELETED
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
const axios = require("axios");
|
|
2
|
-
const { google } = require("googleapis");
|
|
3
|
-
|
|
4
|
-
const GOOGLE_DRIVE_UPDATE_TYPES = [
|
|
5
|
-
"add",
|
|
6
|
-
"sync",
|
|
7
|
-
"remove",
|
|
8
|
-
"update",
|
|
9
|
-
"trash",
|
|
10
|
-
"untrash",
|
|
11
|
-
"change",
|
|
12
|
-
];
|
|
13
|
-
|
|
14
|
-
module.exports = {
|
|
15
|
-
type: "app",
|
|
16
|
-
app: "google_drive",
|
|
17
|
-
propDefinitions: {
|
|
18
|
-
watchedDrive: {
|
|
19
|
-
type: "string",
|
|
20
|
-
label: "Drive",
|
|
21
|
-
description: "The drive you want to watch for changes",
|
|
22
|
-
async options({ page, prevContext }) {
|
|
23
|
-
const { nextPageToken } = prevContext;
|
|
24
|
-
return await this.listDrives(nextPageToken);
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
updateTypes: {
|
|
28
|
-
type: "string[]",
|
|
29
|
-
label: "Types of updates",
|
|
30
|
-
description:
|
|
31
|
-
"The types of updates you want to watch for on these files. [See Google's docs](https://developers.google.com/drive/api/v3/push#understanding-drive-api-notification-events).",
|
|
32
|
-
// https://developers.google.com/drive/api/v3/push#understanding-drive-api-notification-events
|
|
33
|
-
default: GOOGLE_DRIVE_UPDATE_TYPES,
|
|
34
|
-
options: GOOGLE_DRIVE_UPDATE_TYPES,
|
|
35
|
-
},
|
|
36
|
-
watchForPropertiesChanges: {
|
|
37
|
-
type: "boolean",
|
|
38
|
-
label: "Watch for changes to file properties",
|
|
39
|
-
description:
|
|
40
|
-
"Watch for changes to [file properties](https://developers.google.com/drive/api/v3/properties) in addition to changes to content. **Defaults to `false`, watching for only changes to content**.",
|
|
41
|
-
optional: true,
|
|
42
|
-
default: false,
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
methods: {
|
|
46
|
-
// Returns a drive object authenticated with the user's access token
|
|
47
|
-
drive() {
|
|
48
|
-
const auth = new google.auth.OAuth2();
|
|
49
|
-
auth.setCredentials({ access_token: this.$auth.oauth_access_token });
|
|
50
|
-
return google.drive({ version: "v3", auth });
|
|
51
|
-
},
|
|
52
|
-
// Google's push notifications provide a URL to the resource that changed,
|
|
53
|
-
// which we can use to fetch the file's metadata. So we use axios here
|
|
54
|
-
// (vs. the Node client) to get that.
|
|
55
|
-
async getFileMetadata(url) {
|
|
56
|
-
return (
|
|
57
|
-
await axios({
|
|
58
|
-
method: "GET",
|
|
59
|
-
headers: {
|
|
60
|
-
Authorization: `Bearer ${this.$auth.oauth_access_token}`,
|
|
61
|
-
},
|
|
62
|
-
url,
|
|
63
|
-
})
|
|
64
|
-
).data;
|
|
65
|
-
},
|
|
66
|
-
async getChanges(pageToken, driveId) {
|
|
67
|
-
const drive = this.drive();
|
|
68
|
-
// As with many of the methods for Google Drive, we must
|
|
69
|
-
// pass a request of a different shape when we're requesting
|
|
70
|
-
// changes for My Drive (null driveId) vs. a shared drive
|
|
71
|
-
let changeRequest;
|
|
72
|
-
if (driveId) {
|
|
73
|
-
changeRequest = {
|
|
74
|
-
driveId,
|
|
75
|
-
pageToken,
|
|
76
|
-
includeItemsFromAllDrives: true,
|
|
77
|
-
supportsAllDrives: true,
|
|
78
|
-
};
|
|
79
|
-
} else {
|
|
80
|
-
changeRequest = {
|
|
81
|
-
pageToken,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
const { changes, newStartPageToken } = (
|
|
85
|
-
await drive.changes.list(changeRequest)
|
|
86
|
-
).data;
|
|
87
|
-
|
|
88
|
-
// Some changes do not include an associated file object. Return only those that do
|
|
89
|
-
const changedFiles = changes
|
|
90
|
-
.map((change) => change.file)
|
|
91
|
-
.filter((f) => typeof f === "object");
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
changedFiles,
|
|
95
|
-
newStartPageToken,
|
|
96
|
-
};
|
|
97
|
-
},
|
|
98
|
-
async getPageToken() {
|
|
99
|
-
const drive = this.drive();
|
|
100
|
-
return (await drive.changes.getStartPageToken({})).data.startPageToken;
|
|
101
|
-
},
|
|
102
|
-
async listDrives(pageToken) {
|
|
103
|
-
const drive = this.drive();
|
|
104
|
-
const resp = await drive.drives.list({ pageToken });
|
|
105
|
-
const { drives, nextPageToken } = resp.data;
|
|
106
|
-
// "My Drive" isn't returned from the list of drives,
|
|
107
|
-
// so we add it to the list and assign it a static
|
|
108
|
-
// ID that we can refer to when we need.
|
|
109
|
-
const options = [{ label: "My Drive", value: "myDrive" }];
|
|
110
|
-
for (const d of drives) {
|
|
111
|
-
options.push({ label: d.name, value: d.id });
|
|
112
|
-
}
|
|
113
|
-
return {
|
|
114
|
-
options,
|
|
115
|
-
context: { nextPageToken },
|
|
116
|
-
};
|
|
117
|
-
},
|
|
118
|
-
async listFiles(opts) {
|
|
119
|
-
const drive = this.drive();
|
|
120
|
-
// Listing files in My Drive and a shared drive requires
|
|
121
|
-
// mutually-exclusive options, so we accept an object of
|
|
122
|
-
// opts from the caller and pass them to the list method.
|
|
123
|
-
const resp = await drive.files.list(opts);
|
|
124
|
-
const { files, nextPageToken } = resp.data;
|
|
125
|
-
const options = files.map((file) => {
|
|
126
|
-
return { label: file.name, value: file.id };
|
|
127
|
-
});
|
|
128
|
-
return {
|
|
129
|
-
options,
|
|
130
|
-
context: { nextPageToken },
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
|
-
_makeWatchRequestBody(id, address) {
|
|
134
|
-
return {
|
|
135
|
-
id, // the component-specific channel ID, a UUID
|
|
136
|
-
type: "web_hook",
|
|
137
|
-
address, // the component-specific HTTP endpoint
|
|
138
|
-
};
|
|
139
|
-
},
|
|
140
|
-
async watchDrive(id, address, pageToken, driveId) {
|
|
141
|
-
const drive = this.drive();
|
|
142
|
-
const requestBody = this._makeWatchRequestBody(id, address);
|
|
143
|
-
|
|
144
|
-
// Google expects an entirely different object to be passed
|
|
145
|
-
// when you make a watch request for My Drive vs. a shared drive
|
|
146
|
-
// "My Drive" doesn't have a driveId, so if this method is called
|
|
147
|
-
// without a driveId, we make a watch request for My Drive
|
|
148
|
-
let watchRequest;
|
|
149
|
-
if (driveId) {
|
|
150
|
-
watchRequest = {
|
|
151
|
-
driveId,
|
|
152
|
-
pageToken,
|
|
153
|
-
requestBody,
|
|
154
|
-
includeItemsFromAllDrives: true,
|
|
155
|
-
supportsAllDrives: true,
|
|
156
|
-
};
|
|
157
|
-
} else {
|
|
158
|
-
watchRequest = {
|
|
159
|
-
pageToken,
|
|
160
|
-
requestBody,
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
// When watching for changes to an entire account, we must pass a pageToken,
|
|
164
|
-
// which points to the moment in time we want to start watching for changes:
|
|
165
|
-
// https://developers.google.com/drive/api/v3/manage-changes
|
|
166
|
-
const { expiration, resourceId } = (
|
|
167
|
-
await drive.changes.watch(watchRequest)
|
|
168
|
-
).data;
|
|
169
|
-
console.log(`Watch request for drive successful, expiry: ${expiration}`);
|
|
170
|
-
return {
|
|
171
|
-
expiration: parseInt(expiration),
|
|
172
|
-
resourceId,
|
|
173
|
-
};
|
|
174
|
-
},
|
|
175
|
-
async watchFile(id, address, fileId) {
|
|
176
|
-
const drive = this.drive();
|
|
177
|
-
const requestBody = this._makeWatchRequestBody(id, address);
|
|
178
|
-
const { expiration, resourceId } = (
|
|
179
|
-
await drive.files.watch({
|
|
180
|
-
fileId,
|
|
181
|
-
requestBody,
|
|
182
|
-
supportsAllDrives: true,
|
|
183
|
-
})
|
|
184
|
-
).data;
|
|
185
|
-
console.log(
|
|
186
|
-
`Watch request for file ${fileId} successful, expiry: ${expiration}`
|
|
187
|
-
);
|
|
188
|
-
return {
|
|
189
|
-
expiration: parseInt(expiration),
|
|
190
|
-
resourceId,
|
|
191
|
-
};
|
|
192
|
-
},
|
|
193
|
-
async stopNotifications(id, resourceId) {
|
|
194
|
-
// id = channelID
|
|
195
|
-
// See https://github.com/googleapis/google-api-nodejs-client/issues/627
|
|
196
|
-
const drive = this.drive();
|
|
197
|
-
|
|
198
|
-
// If for some reason the channel doesn't exist, this throws an error
|
|
199
|
-
// It's OK for this to fail in those cases, since we'll renew the channel
|
|
200
|
-
// immediately after trying to stop it if we still want notifications,
|
|
201
|
-
// so we squash the error, log it, and move on.
|
|
202
|
-
try {
|
|
203
|
-
await drive.channels.stop({ resource: { id, resourceId } });
|
|
204
|
-
console.log(`Stopped push notifications on channel ${id}`);
|
|
205
|
-
} catch (err) {
|
|
206
|
-
console.error(
|
|
207
|
-
`Failed to stop channel ${id} for resource ${resourceId}: ${err}`
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
};
|