import {
GOOGLE_DRIVE_NOTIFICATION_ADD,
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
} from "../../common/constants.mjs";
import common from "../common-webhook.mjs";
export default {
...common,
key: "google_drive-new-or-modified-folders",
name: "New or Modified Folders (Instant)",
description: "Emit new event when a folder is created or modified in the selected Drive",
version: "0.2.0",
type: "source",
dedupe: "unique",
props: {
...common.props,
folderId: {
propDefinition: [
common.props.googleDrive,
"folderId",
(c) => ({
drive: c.drive,
}),
],
label: "Parent Folder",
description: "The ID of the parent folder which contains the folders. If not specified, it will watch all folders from the drive's top-level folder.",
optional: true,
},
includeSubfolders: {
type: "boolean",
label: "Include Subfolders",
description: "Whether to include subfolders of the parent folder in the changes.",
optional: true,
},
},
hooks: {
async deploy() {
const daysAgo = new Date();
daysAgo.setDate(daysAgo.getDate() - 30);
const timeString = daysAgo.toISOString();
const args = this.getListFilesOpts({
q: `mimeType = "application/vnd.google-apps.folder" and modifiedTime > "${timeString}" and trashed = false`,
fields: "files(id, mimeType)",
});
const { files } = await this.googleDrive.listFilesInPage(null, args);
await this.processChanges(files, null, 5);
},
...common.hooks,
},
methods: {
...common.methods,
_getLastModifiedTimeForFile(fileId) {
return this.db.get(fileId);
},
_setModifiedTimeForFile(fileId, modifiedTime) {
this.db.set(fileId, modifiedTime);
},
getUpdateTypes() {
return [
GOOGLE_DRIVE_NOTIFICATION_ADD,
GOOGLE_DRIVE_NOTIFICATION_CHANGE,
GOOGLE_DRIVE_NOTIFICATION_UPDATE,
];
},
async getAllParents(folderId) {
const allParents = [];
let currentId = folderId;
while (currentId) {
const folder = await this.googleDrive.getFile(currentId, {
fields: "parents",
});
const parents = folder.parents;
if (parents && parents.length > 0) {
allParents.push(parents[0]);
}
currentId = parents?.[0];
}
return allParents;
},
generateMeta(data, ts) {
const {
id: fileId,
name: summary,
} = data;
return {
id: `${fileId}-${ts}`,
summary,
ts,
};
},
async getChanges(headers) {
if (!headers) {
return {
change: { },
};
}
const resourceUri = headers["x-goog-resource-uri"];
const metadata = await this.googleDrive.getFileMetadata(`${resourceUri}&fields=*`);
return {
...metadata,
change: {
state: headers["x-goog-resource-state"],
resourceURI: headers["x-goog-resource-uri"],
changed: headers["x-goog-changed"],
},
};
},
async processChanges(changedFiles, headers, maxResults) {
const files = changedFiles.filter(
(file) => file.mimeType === "application/vnd.google-apps.folder",
);
const filteredFiles = [];
for (const file of files) {
const fileInfo = await this.googleDrive.getFile(file.id);
const root = await this.googleDrive.getFile(this.drive === "My Drive"
? "root"
: this.drive);
const allParents = [];
if (this.includeSubfolders) {
allParents.push(...(await this.getAllParents(file.id)));
} else {
allParents.push(fileInfo.parents[0]);
}
if (!allParents.includes(this.folderId || root.id)) {
continue;
}
filteredFiles.push(fileInfo);
}
if (maxResults && filteredFiles.length >= maxResults) {
filteredFiles.length = maxResults;
}
for (const file of filteredFiles) {
const lastModifiedTimeForFile = this._getLastModifiedTimeForFile(file.id);
const modifiedTime = Date.parse(file.modifiedTime);
if (lastModifiedTimeForFile == modifiedTime) continue;
const changes = await this.getChanges(headers);
const eventToEmit = {
file,
...changes,
};
const meta = this.generateMeta(file, modifiedTime);
this.$emit(eventToEmit, meta);
this._setModifiedTimeForFile(file.id, modifiedTime);
}
},
},
};