sources/new-or-modified-folders/new-or-modified-folders.mjs
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.3", 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); } }, }, };