UNPKG

n8n-nodes-service-account-google-drive

Version:
1,068 lines 46.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GoogleDriveServiceAccount = void 0; const n8n_workflow_1 = require("n8n-workflow"); const googleapis_1 = require("googleapis"); class GoogleDriveServiceAccount { constructor() { this.description = { displayName: 'Google Drive (Service Account)', name: 'googleDriveServiceAccount', icon: 'file:googleDrive.svg', group: ['transform'], version: 1, subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}', description: 'Access Google Drive API using Service Account', defaults: { name: 'Google Drive SA', }, inputs: ['main'], outputs: ['main'], credentials: [ { name: 'googleDriveServiceAccountApi', required: false, }, ], properties: [ // Authentication Type Selector { displayName: 'Authentication', name: 'authType', type: 'options', noDataExpression: true, options: [ { name: 'Credential', value: 'credential', description: 'Use saved n8n credentials', }, { name: 'Manual', value: 'manual', description: 'Enter credentials manually for each execution', }, ], default: 'credential', description: 'Choose authentication method', }, // Manual Authentication Fields { displayName: 'Service Account Email', name: 'serviceAccountEmail', type: 'string', default: '', required: true, displayOptions: { show: { authType: ['manual'], }, }, description: 'Service account email address (from service account JSON)', }, { displayName: 'Private Key', name: 'privateKey', type: 'string', default: '', required: true, typeOptions: { alwaysOpenEditWindow: true, }, displayOptions: { show: { authType: ['manual'], }, }, description: 'Private key (from service account JSON)', }, { displayName: 'Impersonate Email (Optional)', name: 'impersonateEmail', type: 'string', default: '', required: false, displayOptions: { show: { authType: ['manual'], }, }, description: 'Email of user to impersonate (requires domain-wide delegation)', }, { displayName: 'Resource', name: 'resource', type: 'options', noDataExpression: true, options: [ { name: 'File', value: 'file', }, { name: 'Folder', value: 'folder', }, { name: 'Permission', value: 'permission', }, ], default: 'file', }, // File Operations { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['file'], }, }, options: [ { name: 'Copy', value: 'copy', description: 'Copy a file', action: 'Copy a file', }, { name: 'Create', value: 'create', description: 'Create a file', action: 'Create a file', }, { name: 'Delete', value: 'delete', description: 'Delete a file', action: 'Delete a file', }, { name: 'Download', value: 'download', description: 'Download a file', action: 'Download a file', }, { name: 'Export', value: 'export', description: 'Export a Google Workspace file', action: 'Export a file', }, { name: 'Get', value: 'get', description: 'Get a file', action: 'Get a file', }, { name: 'Import', value: 'import', description: 'Import file converting to Google Workspace format', action: 'Import a file', }, { name: 'List', value: 'list', description: 'List files', action: 'List files', }, { name: 'Move', value: 'move', description: 'Move a file', action: 'Move a file', }, { name: 'Update', value: 'update', description: 'Update a file', action: 'Update a file', }, { name: 'Upload', value: 'upload', description: 'Upload a file', action: 'Upload a file', }, ], default: 'list', }, // Folder Operations { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['folder'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a folder', action: 'Create a folder', }, { name: 'Delete', value: 'delete', description: 'Delete a folder', action: 'Delete a folder', }, { name: 'List', value: 'list', description: 'List folders', action: 'List folders', }, ], default: 'create', }, // Permission Operations { displayName: 'Operation', name: 'operation', type: 'options', noDataExpression: true, displayOptions: { show: { resource: ['permission'], }, }, options: [ { name: 'Create', value: 'create', description: 'Create a permission', action: 'Create a permission', }, { name: 'Delete', value: 'delete', description: 'Delete a permission', action: 'Delete a permission', }, { name: 'Get', value: 'get', description: 'Get a permission', action: 'Get a permission', }, { name: 'List', value: 'list', description: 'List permissions', action: 'List permissions', }, { name: 'Update', value: 'update', description: 'Update a permission', action: 'Update a permission', }, ], default: 'create', }, // File ID (for most file operations) { displayName: 'File ID', name: 'fileId', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['file'], operation: ['get', 'delete', 'download', 'update', 'copy', 'move', 'export'], }, }, description: 'The ID of the file', }, { displayName: 'File ID', name: 'fileId', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['permission'], }, }, description: 'The ID of the file', }, // Folder ID { displayName: 'Folder ID', name: 'folderId', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['folder'], operation: ['delete'], }, }, description: 'The ID of the folder', }, // Permission ID { displayName: 'Permission ID', name: 'permissionId', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['permission'], operation: ['get', 'delete', 'update'], }, }, description: 'The ID of the permission', }, // Export Format { displayName: 'Export Format', name: 'exportFormat', type: 'options', required: true, displayOptions: { show: { resource: ['file'], operation: ['export'], }, }, options: [ // Google Docs { name: 'PDF', value: 'application/pdf' }, { name: 'Microsoft Word (DOCX)', value: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }, { name: 'Rich Text (RTF)', value: 'application/rtf' }, { name: 'Plain Text', value: 'text/plain' }, { name: 'HTML', value: 'text/html' }, { name: 'EPUB', value: 'application/epub+zip' }, // Google Sheets { name: 'Microsoft Excel (XLSX)', value: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }, { name: 'CSV', value: 'text/csv' }, { name: 'TSV', value: 'text/tab-separated-values' }, { name: 'OpenDocument Spreadsheet (ODS)', value: 'application/vnd.oasis.opendocument.spreadsheet' }, // Google Slides { name: 'Microsoft PowerPoint (PPTX)', value: 'application/vnd.openxmlformats-officedocument.presentationml.presentation' }, { name: 'OpenDocument Presentation (ODP)', value: 'application/vnd.oasis.opendocument.presentation' }, // Google Drawings { name: 'JPEG', value: 'image/jpeg' }, { name: 'PNG', value: 'image/png' }, { name: 'SVG', value: 'image/svg+xml' }, ], default: 'application/pdf', description: 'Format to export the file to', }, // File Create/Upload Fields { displayName: 'File Name', name: 'fileName', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['file'], operation: ['create', 'upload', 'import'], }, }, description: 'Name of the file', }, { displayName: 'File Content', name: 'fileContent', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['file'], operation: ['create', 'upload', 'import'], }, }, description: 'Content of the file (text or base64)', }, // Import Convert Type { displayName: 'Convert To', name: 'convertTo', type: 'options', required: true, displayOptions: { show: { resource: ['file'], operation: ['import'], }, }, options: [ { name: 'Google Docs', value: 'application/vnd.google-apps.document' }, { name: 'Google Sheets', value: 'application/vnd.google-apps.spreadsheet' }, { name: 'Google Slides', value: 'application/vnd.google-apps.presentation' }, { name: 'Google Drawings', value: 'application/vnd.google-apps.drawing' }, ], default: 'application/vnd.google-apps.document', description: 'Google Workspace format to convert the file to', }, // Folder Create Fields { displayName: 'Folder Name', name: 'folderName', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['folder'], operation: ['create'], }, }, description: 'Name of the folder', }, // Parent Folder ID { displayName: 'Parent Folder ID', name: 'parentFolderId', type: 'string', default: '', displayOptions: { show: { resource: ['file', 'folder'], operation: ['create', 'upload', 'import'], }, }, description: 'ID of the parent folder (leave empty for root)', }, { displayName: 'New Parent Folder ID', name: 'newParentFolderId', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['file'], operation: ['move'], }, }, description: 'ID of the destination folder', }, // Copy file fields { displayName: 'New File Name', name: 'newFileName', type: 'string', default: '', displayOptions: { show: { resource: ['file'], operation: ['copy'], }, }, description: 'Name for the copied file (optional)', }, // Permission fields { displayName: 'Role', name: 'role', type: 'options', required: true, displayOptions: { show: { resource: ['permission'], operation: ['create', 'update'], }, }, options: [ { name: 'Owner', value: 'owner', }, { name: 'Organizer', value: 'organizer', }, { name: 'File Organizer', value: 'fileOrganizer', }, { name: 'Writer', value: 'writer', }, { name: 'Commenter', value: 'commenter', }, { name: 'Reader', value: 'reader', }, ], default: 'reader', description: 'The role granted by this permission', }, { displayName: 'Type', name: 'permissionType', type: 'options', required: true, displayOptions: { show: { resource: ['permission'], operation: ['create'], }, }, options: [ { name: 'User', value: 'user', }, { name: 'Group', value: 'group', }, { name: 'Domain', value: 'domain', }, { name: 'Anyone', value: 'anyone', }, ], default: 'user', description: 'The type of the grantee', }, { displayName: 'Email Address', name: 'emailAddress', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['permission'], operation: ['create'], permissionType: ['user', 'group'], }, }, description: 'Email address of the user or group', }, { displayName: 'Domain', name: 'domain', type: 'string', default: '', required: true, displayOptions: { show: { resource: ['permission'], operation: ['create'], permissionType: ['domain'], }, }, description: 'The domain name', }, // List Options { displayName: 'Options', name: 'options', type: 'collection', placeholder: 'Add Option', default: {}, displayOptions: { show: { resource: ['file', 'folder'], operation: ['list'], }, }, options: [ { displayName: 'Query', name: 'q', type: 'string', default: '', description: 'Query string for filtering files (e.g., name contains "report")', }, { displayName: 'Page Size', name: 'pageSize', type: 'number', default: 100, description: 'Maximum number of files to return', }, { displayName: 'Order By', name: 'orderBy', type: 'string', default: '', description: 'Sort order (e.g., "createdTime desc")', }, { displayName: 'Fields', name: 'fields', type: 'string', default: '*', description: 'Fields to return (e.g., "files(id,name,mimeType)")', }, ], }, // Update Options { displayName: 'Update Fields', name: 'updateFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['file'], operation: ['update'], }, }, options: [ { displayName: 'Name', name: 'name', type: 'string', default: '', description: 'New name for the file', }, { displayName: 'Description', name: 'description', type: 'string', default: '', description: 'New description for the file', }, { displayName: 'Starred', name: 'starred', type: 'boolean', default: false, description: 'Whether the file is starred', }, { displayName: 'Trashed', name: 'trashed', type: 'boolean', default: false, description: 'Whether the file is trashed', }, ], }, // Additional Options { displayName: 'Additional Fields', name: 'additionalFields', type: 'collection', placeholder: 'Add Field', default: {}, displayOptions: { show: { resource: ['file'], operation: ['create', 'upload', 'import'], }, }, options: [ { displayName: 'Description', name: 'description', type: 'string', default: '', description: 'Description of the file', }, { displayName: 'MIME Type', name: 'mimeType', type: 'string', default: '', description: 'MIME type of the file (for upload/create operations)', }, ], }, { displayName: 'Options', name: 'permissionOptions', type: 'collection', placeholder: 'Add Option', default: {}, displayOptions: { show: { resource: ['permission'], operation: ['create'], }, }, options: [ { displayName: 'Send Notification Email', name: 'sendNotificationEmail', type: 'boolean', default: true, description: 'Whether to send a notification email', }, { displayName: 'Email Message', name: 'emailMessage', type: 'string', default: '', description: 'A custom message to include in the notification email', }, ], }, ], }; } async execute() { var _a; const items = this.getInputData(); const returnData = []; const authType = this.getNodeParameter('authType', 0); let serviceAccountEmail; let privateKey; let impersonateEmail; if (authType === 'credential') { const credentials = await this.getCredentials('googleDriveServiceAccountApi'); if (!credentials) { throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No credentials provided. Please select a credential or switch to Manual authentication.'); } serviceAccountEmail = credentials.serviceAccountEmail; privateKey = credentials.privateKey.replace(/\\n/g, '\n'); impersonateEmail = credentials.impersonateEmail || undefined; } else { serviceAccountEmail = this.getNodeParameter('serviceAccountEmail', 0); privateKey = this.getNodeParameter('privateKey', 0).replace(/\\n/g, '\n'); impersonateEmail = this.getNodeParameter('impersonateEmail', 0) || undefined; } // Setup JWT auth with service account const auth = new googleapis_1.google.auth.JWT({ email: serviceAccountEmail, key: privateKey, scopes: ['https://www.googleapis.com/auth/drive'], subject: impersonateEmail, }); const drive = googleapis_1.google.drive({ version: 'v3', auth }); const resource = this.getNodeParameter('resource', 0); const operation = this.getNodeParameter('operation', 0); for (let i = 0; i < items.length; i++) { try { if (resource === 'file') { if (operation === 'list') { const options = this.getNodeParameter('options', i); const params = { pageSize: options.pageSize || 100, fields: options.fields || 'files(id, name, mimeType, createdTime, modifiedTime, size, parents)', }; if (options.q) { params.q = options.q; } if (options.orderBy) { params.orderBy = options.orderBy; } const response = await drive.files.list(params); const files = response.data.files || []; files.forEach((file) => { returnData.push({ json: file }); }); } else if (operation === 'get') { const fileId = this.getNodeParameter('fileId', i); const response = await drive.files.get({ fileId, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'create' || operation === 'upload') { const fileName = this.getNodeParameter('fileName', i); const fileContent = this.getNodeParameter('fileContent', i); const parentFolderId = this.getNodeParameter('parentFolderId', i); const additionalFields = this.getNodeParameter('additionalFields', i); const fileMetadata = { name: fileName, }; if (parentFolderId) { fileMetadata.parents = [parentFolderId]; } if (additionalFields.description) { fileMetadata.description = additionalFields.description; } if (additionalFields.mimeType) { fileMetadata.mimeType = additionalFields.mimeType; } const media = { mimeType: additionalFields.mimeType || 'text/plain', body: fileContent, }; const response = await drive.files.create({ requestBody: fileMetadata, media: media, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'delete') { const fileId = this.getNodeParameter('fileId', i); await drive.files.delete({ fileId, }); returnData.push({ json: { success: true, fileId } }); } else if (operation === 'download') { const fileId = this.getNodeParameter('fileId', i); const response = await drive.files.get({ fileId, alt: 'media', }, { responseType: 'text' }); returnData.push({ json: { fileId, content: response.data } }); } else if (operation === 'update') { const fileId = this.getNodeParameter('fileId', i); const updateFields = this.getNodeParameter('updateFields', i); const fileMetadata = {}; if (updateFields.name) { fileMetadata.name = updateFields.name; } if (updateFields.description !== undefined) { fileMetadata.description = updateFields.description; } if (updateFields.starred !== undefined) { fileMetadata.starred = updateFields.starred; } if (updateFields.trashed !== undefined) { fileMetadata.trashed = updateFields.trashed; } const response = await drive.files.update({ fileId, requestBody: fileMetadata, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'copy') { const fileId = this.getNodeParameter('fileId', i); const newFileName = this.getNodeParameter('newFileName', i); const fileMetadata = {}; if (newFileName) { fileMetadata.name = newFileName; } const response = await drive.files.copy({ fileId, requestBody: fileMetadata, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'move') { const fileId = this.getNodeParameter('fileId', i); const newParentFolderId = this.getNodeParameter('newParentFolderId', i); // Get current parents const file = await drive.files.get({ fileId, fields: 'parents', }); const previousParents = ((_a = file.data.parents) === null || _a === void 0 ? void 0 : _a.join(',')) || ''; const response = await drive.files.update({ fileId, addParents: newParentFolderId, removeParents: previousParents, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'export') { const fileId = this.getNodeParameter('fileId', i); const exportFormat = this.getNodeParameter('exportFormat', i); const response = await drive.files.export({ fileId, mimeType: exportFormat, }, { responseType: 'text' }); // Get file metadata for name const fileMetadata = await drive.files.get({ fileId, fields: 'name,mimeType', }); returnData.push({ json: { fileId, fileName: fileMetadata.data.name, originalMimeType: fileMetadata.data.mimeType, exportFormat, content: response.data } }); } else if (operation === 'import') { const fileName = this.getNodeParameter('fileName', i); const fileContent = this.getNodeParameter('fileContent', i); const convertTo = this.getNodeParameter('convertTo', i); const parentFolderId = this.getNodeParameter('parentFolderId', i); const additionalFields = this.getNodeParameter('additionalFields', i); const fileMetadata = { name: fileName, mimeType: convertTo, }; if (parentFolderId) { fileMetadata.parents = [parentFolderId]; } if (additionalFields.description) { fileMetadata.description = additionalFields.description; } // Determine source MIME type based on conversion target let sourceMimeType = additionalFields.mimeType || 'text/plain'; const media = { mimeType: sourceMimeType, body: fileContent, }; const response = await drive.files.create({ requestBody: fileMetadata, media: media, fields: '*', }); returnData.push({ json: Object.assign(Object.assign({}, response.data), { convertedTo: convertTo }) }); } } else if (resource === 'folder') { if (operation === 'create') { const folderName = this.getNodeParameter('folderName', i); const parentFolderId = this.getNodeParameter('parentFolderId', i); const fileMetadata = { name: folderName, mimeType: 'application/vnd.google-apps.folder', }; if (parentFolderId) { fileMetadata.parents = [parentFolderId]; } const response = await drive.files.create({ requestBody: fileMetadata, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'delete') { const folderId = this.getNodeParameter('folderId', i); await drive.files.delete({ fileId: folderId, }); returnData.push({ json: { success: true, folderId } }); } else if (operation === 'list') { const options = this.getNodeParameter('options', i); const params = { q: "mimeType='application/vnd.google-apps.folder'", pageSize: options.pageSize || 100, fields: options.fields || 'files(id, name, createdTime, modifiedTime, parents)', }; if (options.q) { params.q += ` and (${options.q})`; } if (options.orderBy) { params.orderBy = options.orderBy; } const response = await drive.files.list(params); const folders = response.data.files || []; folders.forEach((folder) => { returnData.push({ json: folder }); }); } } else if (resource === 'permission') { const fileId = this.getNodeParameter('fileId', i); if (operation === 'create') { const role = this.getNodeParameter('role', i); const permissionType = this.getNodeParameter('permissionType', i); const permissionOptions = this.getNodeParameter('permissionOptions', i); const permission = { type: permissionType, role, }; if (permissionType === 'user' || permissionType === 'group') { const emailAddress = this.getNodeParameter('emailAddress', i); permission.emailAddress = emailAddress; } if (permissionType === 'domain') { const domain = this.getNodeParameter('domain', i); permission.domain = domain; } const params = { fileId, requestBody: permission, fields: '*', }; if (permissionOptions.sendNotificationEmail !== undefined) { params.sendNotificationEmail = permissionOptions.sendNotificationEmail; } if (permissionOptions.emailMessage) { params.emailMessage = permissionOptions.emailMessage; } const response = await drive.permissions.create(params); returnData.push({ json: response.data }); } else if (operation === 'list') { const response = await drive.permissions.list({ fileId, fields: '*', }); const permissions = response.data.permissions || []; permissions.forEach((permission) => { returnData.push({ json: permission }); }); } else if (operation === 'get') { const permissionId = this.getNodeParameter('permissionId', i); const response = await drive.permissions.get({ fileId, permissionId, fields: '*', }); returnData.push({ json: response.data }); } else if (operation === 'delete') { const permissionId = this.getNodeParameter('permissionId', i); await drive.permissions.delete({ fileId, permissionId, }); returnData.push({ json: { success: true, permissionId } }); } else if (operation === 'update') { const permissionId = this.getNodeParameter('permissionId', i); const role = this.getNodeParameter('role', i); const response = await drive.permissions.update({ fileId, permissionId, requestBody: { role, }, fields: '*', }); returnData.push({ json: response.data }); } } } catch (error) { if (this.continueOnFail()) { returnData.push({ json: { error: error.message } }); continue; } throw new n8n_workflow_1.NodeOperationError(this.getNode(), error); } } return [returnData]; } } exports.GoogleDriveServiceAccount = GoogleDriveServiceAccount; //# sourceMappingURL=GoogleDriveServiceAccount.node.js.map