@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
package/sources/changes-to-specific-files-shared-drive/changes-to-specific-files-shared-drive.mjs
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// This source processes changes to specific files in a user's Google Drive,
|
|
2
|
+
// implementing strategy enumerated in the Push Notifications API docs:
|
|
3
|
+
// https://developers.google.com/drive/api/v3/push .
|
|
4
|
+
//
|
|
5
|
+
// This source has two interfaces:
|
|
6
|
+
//
|
|
7
|
+
// 1) The HTTP requests tied to changes in files in the user's Google Drive
|
|
8
|
+
// 2) A timer that runs on regular intervals, renewing the notification channel as needed
|
|
9
|
+
|
|
10
|
+
import common from "../common-webhook.mjs";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
14
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
15
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
16
|
+
} from "../../constants.mjs";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* This source uses the Google Drive API's
|
|
20
|
+
* {@link https://developers.google.com/drive/api/v3/reference/changes/watch changes: watch}
|
|
21
|
+
* endpoint to subscribe to changes to the user's drive or a shard drive.
|
|
22
|
+
*/
|
|
23
|
+
export default {
|
|
24
|
+
...common,
|
|
25
|
+
key: "google_drive-changes-to-specific-files-shared-drive",
|
|
26
|
+
name: "Changes to Specific Files (Shared Drive)",
|
|
27
|
+
description: "Watches for changes to specific files in a shared drive, emitting an event any time a change is made to one of those files",
|
|
28
|
+
version: "0.0.1",
|
|
29
|
+
type: "source",
|
|
30
|
+
// Dedupe events based on the "x-goog-message-number" header for the target channel:
|
|
31
|
+
// https://developers.google.com/drive/api/v3/push#making-watch-requests
|
|
32
|
+
dedupe: "unique",
|
|
33
|
+
props: {
|
|
34
|
+
...common.props,
|
|
35
|
+
files: {
|
|
36
|
+
type: "string[]",
|
|
37
|
+
label: "Files",
|
|
38
|
+
description: "The files you want to watch for changes.",
|
|
39
|
+
optional: true,
|
|
40
|
+
default: [],
|
|
41
|
+
options({ prevContext }) {
|
|
42
|
+
const { nextPageToken } = prevContext;
|
|
43
|
+
const baseOpts = {};
|
|
44
|
+
const opts = this.isMyDrive()
|
|
45
|
+
? baseOpts
|
|
46
|
+
: {
|
|
47
|
+
...baseOpts,
|
|
48
|
+
corpora: "drive",
|
|
49
|
+
driveId: this.getDriveId(),
|
|
50
|
+
includeItemsFromAllDrives: true,
|
|
51
|
+
supportsAllDrives: true,
|
|
52
|
+
};
|
|
53
|
+
return this.googleDrive.listFilesOptions(nextPageToken, opts);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
methods: {
|
|
58
|
+
...common.methods,
|
|
59
|
+
getUpdateTypes() {
|
|
60
|
+
return [
|
|
61
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
62
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
63
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
64
|
+
];
|
|
65
|
+
},
|
|
66
|
+
generateMeta(data, headers) {
|
|
67
|
+
const {
|
|
68
|
+
id: fileId,
|
|
69
|
+
name: fileName,
|
|
70
|
+
modifiedTime: tsString,
|
|
71
|
+
} = data;
|
|
72
|
+
const {
|
|
73
|
+
"x-goog-message-number": eventId,
|
|
74
|
+
"x-goog-resource-state": resourceState,
|
|
75
|
+
} = headers;
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
id: `${fileId}-${eventId}`,
|
|
79
|
+
summary: `${resourceState.toUpperCase()} - ${
|
|
80
|
+
fileName || "Untitled"
|
|
81
|
+
}`,
|
|
82
|
+
ts: Date.parse(tsString),
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
isFileRelevant(file) {
|
|
86
|
+
return this.files.includes(file.id);
|
|
87
|
+
},
|
|
88
|
+
async processChange(file, headers) {
|
|
89
|
+
const eventToEmit = {
|
|
90
|
+
file,
|
|
91
|
+
change: {
|
|
92
|
+
state: headers["x-goog-resource-state"],
|
|
93
|
+
resourceURI: headers["x-goog-resource-uri"],
|
|
94
|
+
changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
const meta = this.generateMeta(file, headers);
|
|
98
|
+
this.$emit(eventToEmit, meta);
|
|
99
|
+
},
|
|
100
|
+
async processChanges(changedFiles, headers) {
|
|
101
|
+
for (const file of changedFiles) {
|
|
102
|
+
if (!this.isFileRelevant(file)) {
|
|
103
|
+
console.log(`Skipping event for irrelevant file ${file.id}`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
this.processChange(file, headers);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import includes from "lodash/includes.js";
|
|
2
|
+
import { v4 as uuid } from "uuid";
|
|
3
|
+
|
|
4
|
+
import googleDrive from "../google_drive.app.mjs";
|
|
5
|
+
import { WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS } from "../constants.mjs";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
props: {
|
|
9
|
+
googleDrive,
|
|
10
|
+
db: "$.service.db",
|
|
11
|
+
http: "$.interface.http",
|
|
12
|
+
drive: {
|
|
13
|
+
propDefinition: [
|
|
14
|
+
googleDrive,
|
|
15
|
+
"watchedDrive",
|
|
16
|
+
],
|
|
17
|
+
description: "Defaults to My Drive. To select a [Shared Drive](https://support.google.com/a/users/answer/9310351) instead, select it from this list.",
|
|
18
|
+
optional: false,
|
|
19
|
+
},
|
|
20
|
+
watchForPropertiesChanges: {
|
|
21
|
+
propDefinition: [
|
|
22
|
+
googleDrive,
|
|
23
|
+
"watchForPropertiesChanges",
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
timer: {
|
|
27
|
+
label: "Push notification renewal schedule",
|
|
28
|
+
description:
|
|
29
|
+
"The Google Drive API requires occasional renewal of push notification subscriptions. **This runs in the background, so you should not need to modify this schedule**.",
|
|
30
|
+
type: "$.interface.timer",
|
|
31
|
+
static: {
|
|
32
|
+
intervalSeconds: WEBHOOK_SUBSCRIPTION_RENEWAL_SECONDS,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
hooks: {
|
|
37
|
+
async activate() {
|
|
38
|
+
// Called when a component is created or updated. Handles all the logic
|
|
39
|
+
// for starting and stopping watch notifications tied to the desired
|
|
40
|
+
// files.
|
|
41
|
+
const channelID = uuid();
|
|
42
|
+
const {
|
|
43
|
+
startPageToken,
|
|
44
|
+
expiration,
|
|
45
|
+
resourceId,
|
|
46
|
+
} = await this.googleDrive.activateHook(
|
|
47
|
+
channelID,
|
|
48
|
+
this.http.endpoint,
|
|
49
|
+
this.getDriveId(),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// We use and increment the pageToken as new changes arrive, in run()
|
|
53
|
+
this._setPageToken(startPageToken);
|
|
54
|
+
|
|
55
|
+
// Save metadata on the subscription so we can stop / renew later
|
|
56
|
+
// Subscriptions are tied to Google's resourceID, "an opaque value that
|
|
57
|
+
// identifies the watched resource". This value is included in request headers
|
|
58
|
+
this._setSubscription({
|
|
59
|
+
resourceId,
|
|
60
|
+
expiration,
|
|
61
|
+
});
|
|
62
|
+
this._setChannelID(channelID);
|
|
63
|
+
},
|
|
64
|
+
async deactivate() {
|
|
65
|
+
const channelID = this._getChannelID();
|
|
66
|
+
const { resourceId } = this._getSubscription();
|
|
67
|
+
await this.googleDrive.deactivateHook(channelID, resourceId);
|
|
68
|
+
|
|
69
|
+
this._setSubscription(null);
|
|
70
|
+
this._setChannelID(null);
|
|
71
|
+
this._setPageToken(null);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
methods: {
|
|
75
|
+
_getSubscription() {
|
|
76
|
+
return this.db.get("subscription");
|
|
77
|
+
},
|
|
78
|
+
_setSubscription(subscription) {
|
|
79
|
+
this.db.set("subscription", subscription);
|
|
80
|
+
},
|
|
81
|
+
_getChannelID() {
|
|
82
|
+
return this.db.get("channelID");
|
|
83
|
+
},
|
|
84
|
+
_setChannelID(channelID) {
|
|
85
|
+
this.db.set("channelID", channelID);
|
|
86
|
+
},
|
|
87
|
+
_getPageToken() {
|
|
88
|
+
return this.db.get("pageToken");
|
|
89
|
+
},
|
|
90
|
+
_setPageToken(pageToken) {
|
|
91
|
+
this.db.set("pageToken", pageToken);
|
|
92
|
+
},
|
|
93
|
+
isMyDrive(drive = this.drive) {
|
|
94
|
+
return googleDrive.methods.isMyDrive(drive);
|
|
95
|
+
},
|
|
96
|
+
getDriveId(drive = this.drive) {
|
|
97
|
+
return googleDrive.methods.getDriveId(drive);
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* This method returns the types of updates/events from Google Drive that
|
|
101
|
+
* the event source should listen to. This base implementation returns an
|
|
102
|
+
* empty list, which means that any event source that extends this module
|
|
103
|
+
* and that does not refine this implementation will essentially ignore
|
|
104
|
+
* every incoming event from Google Drive.
|
|
105
|
+
*
|
|
106
|
+
* @returns
|
|
107
|
+
* @type {UpdateType[]}
|
|
108
|
+
*/
|
|
109
|
+
getUpdateTypes() {
|
|
110
|
+
return [];
|
|
111
|
+
},
|
|
112
|
+
/**
|
|
113
|
+
* This method is responsible for processing a list of changed files
|
|
114
|
+
* according to the event source's purpose. As an abstract method, it must
|
|
115
|
+
* be implemented by every event source that extends this module.
|
|
116
|
+
*
|
|
117
|
+
* @param {object[]} [changedFiles] - the list of file changes, as [defined
|
|
118
|
+
* by the API](https://bit.ly/3h7WeUa)
|
|
119
|
+
* @param {object} [headers] - an object containing the request headers of
|
|
120
|
+
* the webhook call made by Google Drive
|
|
121
|
+
*/
|
|
122
|
+
processChanges() {
|
|
123
|
+
throw new Error("processChanges is not implemented");
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
async run(event) {
|
|
127
|
+
// This function is polymorphic: it can be triggered as a cron job, to make
|
|
128
|
+
// sure we renew watch requests for specific files, or via HTTP request (the
|
|
129
|
+
// change payloads from Google)
|
|
130
|
+
const subscription = this._getSubscription();
|
|
131
|
+
const channelID = this._getChannelID();
|
|
132
|
+
const pageToken = this._getPageToken();
|
|
133
|
+
|
|
134
|
+
// Component was invoked by timer
|
|
135
|
+
if (event.timestamp) {
|
|
136
|
+
const {
|
|
137
|
+
newChannelID,
|
|
138
|
+
newPageToken,
|
|
139
|
+
expiration,
|
|
140
|
+
resourceId,
|
|
141
|
+
} = await this.googleDrive.renewSubscription(
|
|
142
|
+
this.drive,
|
|
143
|
+
subscription,
|
|
144
|
+
this.http.endpoint,
|
|
145
|
+
channelID,
|
|
146
|
+
pageToken,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
this._setSubscription({
|
|
150
|
+
expiration,
|
|
151
|
+
resourceId,
|
|
152
|
+
});
|
|
153
|
+
this._setChannelID(newChannelID);
|
|
154
|
+
this._setPageToken(newPageToken);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const { headers } = event;
|
|
159
|
+
if (!this.googleDrive.checkHeaders(headers, subscription, channelID)) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!includes(this.getUpdateTypes(), headers["x-goog-resource-state"])) {
|
|
164
|
+
console.log(
|
|
165
|
+
`Update type ${headers["x-goog-resource-state"]} not in list of updates to watch: `,
|
|
166
|
+
this.getUpdateTypes(),
|
|
167
|
+
);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// We observed false positives where a single change to a document would trigger two changes:
|
|
172
|
+
// one to "properties" and another to "content,properties". But changes to properties
|
|
173
|
+
// alone are legitimate, most users just won't want this source to emit in those cases.
|
|
174
|
+
// If x-goog-changed is _only_ set to "properties", only move on if the user set the prop
|
|
175
|
+
if (
|
|
176
|
+
!this.watchForPropertiesChanges &&
|
|
177
|
+
headers["x-goog-changed"] === "properties"
|
|
178
|
+
) {
|
|
179
|
+
console.log(
|
|
180
|
+
"Change to properties only, which this component is set to ignore. Exiting",
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const driveId = this.getDriveId();
|
|
186
|
+
const changedFilesStream = this.googleDrive.listChanges(pageToken, driveId);
|
|
187
|
+
for await (const changedFilesPage of changedFilesStream) {
|
|
188
|
+
const {
|
|
189
|
+
changedFiles,
|
|
190
|
+
nextPageToken,
|
|
191
|
+
} = changedFilesPage;
|
|
192
|
+
|
|
193
|
+
// Process all the changed files retrieved from the current page
|
|
194
|
+
await this.processChanges(changedFiles, headers);
|
|
195
|
+
|
|
196
|
+
// After successfully processing the changed files, we store the page
|
|
197
|
+
// token of the next page
|
|
198
|
+
this._setPageToken(nextPageToken);
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import common from "../common-webhook.mjs";
|
|
2
|
+
import {
|
|
3
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
4
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
5
|
+
} from "../../constants.mjs";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
...common,
|
|
9
|
+
key: "google_drive-new-files-instant",
|
|
10
|
+
name: "New Files (Instant)",
|
|
11
|
+
description: "Emit new event any time a new file is added in your linked Google Drive",
|
|
12
|
+
version: "0.0.15",
|
|
13
|
+
type: "source",
|
|
14
|
+
dedupe: "unique",
|
|
15
|
+
props: {
|
|
16
|
+
...common.props,
|
|
17
|
+
folders: {
|
|
18
|
+
type: "string[]",
|
|
19
|
+
label: "Folders",
|
|
20
|
+
description:
|
|
21
|
+
"(Optional) The folders you want to watch for changes. Leave blank to watch for any new file in the Drive.",
|
|
22
|
+
optional: true,
|
|
23
|
+
default: [],
|
|
24
|
+
options({ prevContext }) {
|
|
25
|
+
const { nextPageToken } = prevContext;
|
|
26
|
+
const baseOpts = {
|
|
27
|
+
q: "mimeType = 'application/vnd.google-apps.folder'",
|
|
28
|
+
};
|
|
29
|
+
const opts = this.isMyDrive()
|
|
30
|
+
? baseOpts
|
|
31
|
+
: {
|
|
32
|
+
...baseOpts,
|
|
33
|
+
corpora: "drive",
|
|
34
|
+
driveId: this.getDriveId(),
|
|
35
|
+
includeItemsFromAllDrives: true,
|
|
36
|
+
supportsAllDrives: true,
|
|
37
|
+
};
|
|
38
|
+
return this.googleDrive.listFilesOptions(nextPageToken, opts);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
hooks: {
|
|
43
|
+
...common.hooks,
|
|
44
|
+
async activate() {
|
|
45
|
+
await common.hooks.activate.bind(this)();
|
|
46
|
+
this._setLastFileCreatedTime(Date.now());
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
methods: {
|
|
50
|
+
...common.methods,
|
|
51
|
+
_getLastFileCreatedTime() {
|
|
52
|
+
return this.db.get("lastFileCreatedTime");
|
|
53
|
+
},
|
|
54
|
+
_setLastFileCreatedTime(lastFileCreatedTime) {
|
|
55
|
+
this.db.set("lastFileCreatedTime", lastFileCreatedTime);
|
|
56
|
+
},
|
|
57
|
+
shouldProcess(file) {
|
|
58
|
+
const watchedFolders = new Set(this.folders);
|
|
59
|
+
return (
|
|
60
|
+
watchedFolders.size == 0 ||
|
|
61
|
+
(file.parents && file.parents.some((p) => watchedFolders.has(p)))
|
|
62
|
+
);
|
|
63
|
+
},
|
|
64
|
+
getUpdateTypes() {
|
|
65
|
+
return [
|
|
66
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
67
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
68
|
+
];
|
|
69
|
+
},
|
|
70
|
+
async processChanges(changedFiles) {
|
|
71
|
+
const lastFileCreatedTime = this._getLastFileCreatedTime();
|
|
72
|
+
let maxCreatedTime = lastFileCreatedTime;
|
|
73
|
+
|
|
74
|
+
for (const file of changedFiles) {
|
|
75
|
+
const fileInfo = await this.googleDrive.getFile(file.id);
|
|
76
|
+
const createdTime = Date.parse(fileInfo.createdTime);
|
|
77
|
+
if (
|
|
78
|
+
!this.shouldProcess(fileInfo) ||
|
|
79
|
+
createdTime < lastFileCreatedTime
|
|
80
|
+
) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.$emit(fileInfo, {
|
|
85
|
+
summary: `New File: ${fileInfo.name}`,
|
|
86
|
+
id: file.id,
|
|
87
|
+
ts: createdTime,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
maxCreatedTime = Math.max(createdTime, maxCreatedTime);
|
|
91
|
+
this._setLastFileCreatedTime(maxCreatedTime);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// This source processes changes to any files in a user's Google Drive,
|
|
2
|
+
// implementing strategy enumerated in the Push Notifications API docs:
|
|
3
|
+
// https://developers.google.com/drive/api/v3/push and here:
|
|
4
|
+
// https://developers.google.com/drive/api/v3/manage-changes
|
|
5
|
+
//
|
|
6
|
+
// This source has two interfaces:
|
|
7
|
+
//
|
|
8
|
+
// 1) The HTTP requests tied to changes in the user's Google Drive
|
|
9
|
+
// 2) A timer that runs on regular intervals, renewing the notification channel as needed
|
|
10
|
+
|
|
11
|
+
import common from "../common-webhook.mjs";
|
|
12
|
+
import { GOOGLE_DRIVE_NOTIFICATION_CHANGE } from "../../constants.mjs";
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
...common,
|
|
16
|
+
key: "google_drive-new-or-modified-comments",
|
|
17
|
+
name: "New or Modified Comments",
|
|
18
|
+
description:
|
|
19
|
+
"Emits a new event any time a file comment is added, modified, or deleted in your linked Google Drive",
|
|
20
|
+
version: "0.0.9",
|
|
21
|
+
type: "source",
|
|
22
|
+
// Dedupe events based on the "x-goog-message-number" header for the target channel:
|
|
23
|
+
// https://developers.google.com/drive/api/v3/push#making-watch-requests
|
|
24
|
+
dedupe: "unique",
|
|
25
|
+
hooks: {
|
|
26
|
+
...common.hooks,
|
|
27
|
+
async activate() {
|
|
28
|
+
await common.hooks.activate.bind(this)();
|
|
29
|
+
this._setInitTime(Date.now());
|
|
30
|
+
},
|
|
31
|
+
async deactivate() {
|
|
32
|
+
await common.hooks.deactivate.bind(this)();
|
|
33
|
+
this._setInitTime(null);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
methods: {
|
|
37
|
+
...common.methods,
|
|
38
|
+
_getInitTime() {
|
|
39
|
+
return this.db.get("initTime");
|
|
40
|
+
},
|
|
41
|
+
_setInitTime(initTime) {
|
|
42
|
+
this.db.set("initTime", initTime);
|
|
43
|
+
},
|
|
44
|
+
_getLastCommentTimeForFile(fileId) {
|
|
45
|
+
return this.db.get(fileId) || this._getInitTime();
|
|
46
|
+
},
|
|
47
|
+
_updateLastCommentTimeForFile(fileId, commentTime) {
|
|
48
|
+
this.db.set(fileId, commentTime);
|
|
49
|
+
},
|
|
50
|
+
getUpdateTypes() {
|
|
51
|
+
return [
|
|
52
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
53
|
+
];
|
|
54
|
+
},
|
|
55
|
+
generateMeta(data, headers) {
|
|
56
|
+
const {
|
|
57
|
+
id: commentId,
|
|
58
|
+
content: summary,
|
|
59
|
+
modifiedTime: tsString,
|
|
60
|
+
} = data;
|
|
61
|
+
const { "x-goog-message-number": eventId } = headers;
|
|
62
|
+
return {
|
|
63
|
+
id: `${commentId}-${eventId}`,
|
|
64
|
+
summary,
|
|
65
|
+
ts: Date.parse(tsString),
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
async processChanges(changedFiles, headers) {
|
|
69
|
+
for (const file of changedFiles) {
|
|
70
|
+
const lastCommentTimeForFile = this._getLastCommentTimeForFile(file.id);
|
|
71
|
+
let maxModifiedTime = lastCommentTimeForFile;
|
|
72
|
+
const commentsStream = this.googleDrive.listComments(
|
|
73
|
+
file.id,
|
|
74
|
+
lastCommentTimeForFile,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
for await (const comment of commentsStream) {
|
|
78
|
+
const commentTime = Date.parse(comment.modifiedTime);
|
|
79
|
+
if (commentTime <= lastCommentTimeForFile) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const eventToEmit = {
|
|
84
|
+
comment,
|
|
85
|
+
file,
|
|
86
|
+
change: {
|
|
87
|
+
state: headers["x-goog-resource-state"],
|
|
88
|
+
resourceURI: headers["x-goog-resource-uri"],
|
|
89
|
+
|
|
90
|
+
// Additional details about the changes. Possible values: content,
|
|
91
|
+
// parents, children, permissions.
|
|
92
|
+
changed: headers["x-goog-changed"],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const meta = this.generateMeta(comment, headers);
|
|
96
|
+
this.$emit(eventToEmit, meta);
|
|
97
|
+
|
|
98
|
+
maxModifiedTime = Math.max(maxModifiedTime, commentTime);
|
|
99
|
+
this._updateLastCommentTimeForFile(file.id, maxModifiedTime);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// This source processes changes to any files in a user's Google Drive,
|
|
2
|
+
// implementing strategy enumerated in the Push Notifications API docs:
|
|
3
|
+
// https://developers.google.com/drive/api/v3/push and here:
|
|
4
|
+
// https://developers.google.com/drive/api/v3/manage-changes
|
|
5
|
+
//
|
|
6
|
+
// This source has two interfaces:
|
|
7
|
+
//
|
|
8
|
+
// 1) The HTTP requests tied to changes in the user's Google Drive
|
|
9
|
+
// 2) A timer that runs on regular intervals, renewing the notification channel as needed
|
|
10
|
+
|
|
11
|
+
import common from "../common-webhook.mjs";
|
|
12
|
+
import {
|
|
13
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
14
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
15
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
16
|
+
} from "../../constants.mjs";
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
...common,
|
|
20
|
+
key: "google_drive-new-or-modified-files",
|
|
21
|
+
name: "New or Modified Files",
|
|
22
|
+
description:
|
|
23
|
+
"Emits a new event any time any file in your linked Google Drive is added, modified, or deleted",
|
|
24
|
+
version: "0.0.20",
|
|
25
|
+
type: "source",
|
|
26
|
+
// Dedupe events based on the "x-goog-message-number" header for the target channel:
|
|
27
|
+
// https://developers.google.com/drive/api/v3/push#making-watch-requests
|
|
28
|
+
dedupe: "unique",
|
|
29
|
+
methods: {
|
|
30
|
+
...common.methods,
|
|
31
|
+
getUpdateTypes() {
|
|
32
|
+
return [
|
|
33
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
34
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
35
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
36
|
+
];
|
|
37
|
+
},
|
|
38
|
+
generateMeta(data, headers) {
|
|
39
|
+
const {
|
|
40
|
+
id: fileId,
|
|
41
|
+
name: summary,
|
|
42
|
+
modifiedTime: tsString,
|
|
43
|
+
} = data;
|
|
44
|
+
const { "x-goog-message-number": eventId } = headers;
|
|
45
|
+
return {
|
|
46
|
+
id: `${fileId}-${eventId}`,
|
|
47
|
+
summary,
|
|
48
|
+
ts: Date.parse(tsString),
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
async processChanges(changedFiles, headers) {
|
|
52
|
+
for (const file of changedFiles) {
|
|
53
|
+
const eventToEmit = {
|
|
54
|
+
file,
|
|
55
|
+
change: {
|
|
56
|
+
state: headers["x-goog-resource-state"],
|
|
57
|
+
resourceURI: headers["x-goog-resource-uri"],
|
|
58
|
+
changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
const meta = this.generateMeta(file, headers);
|
|
62
|
+
this.$emit(eventToEmit, meta);
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// This source processes changes to any files in a user's Google Drive,
|
|
2
|
+
// implementing strategy enumerated in the Push Notifications API docs:
|
|
3
|
+
// https://developers.google.com/drive/api/v3/push and here:
|
|
4
|
+
// https://developers.google.com/drive/api/v3/manage-changes
|
|
5
|
+
//
|
|
6
|
+
// This source has two interfaces:
|
|
7
|
+
//
|
|
8
|
+
// 1) The HTTP requests tied to changes in the user's Google Drive
|
|
9
|
+
// 2) A timer that runs on regular intervals, renewing the notification channel as needed
|
|
10
|
+
|
|
11
|
+
import common from "../common-webhook.mjs";
|
|
12
|
+
import {
|
|
13
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
14
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
15
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
16
|
+
} from "../../constants.mjs";
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
...common,
|
|
20
|
+
key: "google_drive-new-or-modified-folders",
|
|
21
|
+
name: "New or Modified Folders",
|
|
22
|
+
description:
|
|
23
|
+
"Emits a new event any time any folder in your linked Google Drive is added, modified, or deleted",
|
|
24
|
+
version: "0.0.9",
|
|
25
|
+
type: "source",
|
|
26
|
+
// Dedupe events based on the "x-goog-message-number" header for the target channel:
|
|
27
|
+
// https://developers.google.com/drive/api/v3/push#making-watch-requests
|
|
28
|
+
dedupe: "unique",
|
|
29
|
+
methods: {
|
|
30
|
+
...common.methods,
|
|
31
|
+
_getLastModifiedTimeForFile(fileId) {
|
|
32
|
+
return this.db.get(fileId);
|
|
33
|
+
},
|
|
34
|
+
_setModifiedTimeForFile(fileId, modifiedTime) {
|
|
35
|
+
this.db.set(fileId, modifiedTime);
|
|
36
|
+
},
|
|
37
|
+
getUpdateTypes() {
|
|
38
|
+
return [
|
|
39
|
+
GOOGLE_DRIVE_NOTIFICATION_ADD,
|
|
40
|
+
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
|
|
41
|
+
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
|
|
42
|
+
];
|
|
43
|
+
},
|
|
44
|
+
generateMeta(data, ts) {
|
|
45
|
+
const {
|
|
46
|
+
id: fileId,
|
|
47
|
+
name: summary,
|
|
48
|
+
} = data;
|
|
49
|
+
return {
|
|
50
|
+
id: `${fileId}-${ts}`,
|
|
51
|
+
summary,
|
|
52
|
+
ts,
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
async processChanges(changedFiles, headers) {
|
|
56
|
+
const files = changedFiles.filter(
|
|
57
|
+
// API docs that define Google Drive folders:
|
|
58
|
+
// https://developers.google.com/drive/api/v3/folder
|
|
59
|
+
(file) => file.mimeType === "application/vnd.google-apps.folder",
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
for (const file of files) {
|
|
63
|
+
// The changelog is updated each time a folder is opened. Check the
|
|
64
|
+
// folder's `modifiedTime` to see if the folder has been modified.
|
|
65
|
+
const fileInfo = await this.googleDrive.getFile(file.id);
|
|
66
|
+
|
|
67
|
+
const lastModifiedTimeForFile = this._getLastModifiedTimeForFile(file.id);
|
|
68
|
+
const modifiedTime = Date.parse(fileInfo.modifiedTime);
|
|
69
|
+
if (lastModifiedTimeForFile == modifiedTime) continue;
|
|
70
|
+
|
|
71
|
+
const eventToEmit = {
|
|
72
|
+
file,
|
|
73
|
+
change: {
|
|
74
|
+
state: headers["x-goog-resource-state"],
|
|
75
|
+
resourceURI: headers["x-goog-resource-uri"],
|
|
76
|
+
changed: headers["x-goog-changed"], // "Additional details about the changes. Possible values: content, parents, children, permissions"
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
const meta = this.generateMeta(file, modifiedTime);
|
|
80
|
+
this.$emit(eventToEmit, meta);
|
|
81
|
+
|
|
82
|
+
this._setModifiedTimeForFile(file.id, modifiedTime);
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
};
|