Pular para conteúdo

GOOGLE DRIVE - Armazenamento de Arquivos

O que é este Node?

O GOOGLE DRIVE é o node responsável por integrar com o Google Drive permitindo fazer upload, download, listar, deletar arquivos e criar pastas diretamente dos seus flows.

Por que este Node existe?

Gerenciar arquivos na nuvem programaticamente é essencial. O GOOGLE DRIVE existe para:

  1. Backup automático: Salvar arquivos recebidos no WhatsApp no Drive
  2. Compartilhamento: Gerar links de arquivos para enviar aos usuários
  3. Organização: Criar estrutura de pastas automaticamente
  4. Arquivo de conversas: Armazenar mídias de atendimentos
  5. Integração de documentos: Sincronizar arquivos entre sistemas

Como funciona internamente?

Quando o GOOGLE DRIVE é executado, o sistema:

  1. Autentica usando OAuth2 com Google (access_token e refresh_token)
  2. Identifica operação (upload, download, list, delete, createFolder)
  3. Conecta à API do Google Drive v3
  4. Executa operação com arquivos/pastas
  5. Retorna resultado com IDs, nomes e links
  6. Se erro: Loga e lança exceção

Código interno (productivity-executors.service.ts:447-541):

async executeGoogleDrive(data: any, variables: Record<string, any>): Promise<any> {
  try {
    this.logger.log('📁 [GOOGLE DRIVE] Executing operation');

    const oauth2Client = new OAuth2Client(
      process.env.GOOGLE_CLIENT_ID,
      process.env.GOOGLE_CLIENT_SECRET,
      process.env.GOOGLE_REDIRECT_URI
    );

    oauth2Client.setCredentials({
      access_token: data.accessToken,
      refresh_token: data.refreshToken,
    });

    const drive = google.drive({ version: 'v3', auth: oauth2Client });

    switch (data.operation) {
      case 'upload':
        const uploadResult = await drive.files.create({
          requestBody: {
            name: data.fileName,
            parents: data.folderId ? [data.folderId] : undefined,
          },
          media: {
            mimeType: data.mimeType,
            body: Buffer.from(data.content, 'base64'),
          },
          fields: 'id,name,webViewLink,webContentLink',
        });
        return {
          success: true,
          fileId: uploadResult.data.id,
          fileName: uploadResult.data.name,
          webViewLink: uploadResult.data.webViewLink,
          webContentLink: uploadResult.data.webContentLink,
        };

      case 'download':
        const downloadResult = await drive.files.get({
          fileId: data.fileId,
          alt: 'media',
        }, {
          responseType: 'arraybuffer',
        });
        return {
          success: true,
          content: Buffer.from(downloadResult.data as ArrayBuffer).toString('base64'),
          mimeType: downloadResult.headers['content-type'],
        };

      case 'list':
        const listResult = await drive.files.list({
          q: data.query || `'${data.folderId || 'root'}' in parents`,
          fields: 'files(id, name, mimeType, size, modifiedTime, webViewLink)',
          pageSize: data.pageSize || 100,
        });
        return {
          success: true,
          files: listResult.data.files,
        };

      case 'delete':
        await drive.files.delete({
          fileId: data.fileId,
        });
        return {
          success: true,
          message: 'File deleted successfully',
        };

      case 'createFolder':
        const createFolderResult = await drive.files.create({
          requestBody: {
            name: data.folderName,
            mimeType: 'application/vnd.google-apps.folder',
            parents: data.parentFolderId ? [data.parentFolderId] : undefined,
          },
          fields: 'id,name,webViewLink',
        });
        return {
          success: true,
          folderId: createFolderResult.data.id,
          folderName: createFolderResult.data.name,
          webViewLink: createFolderResult.data.webViewLink,
        };

      default:
        throw new Error(`Unknown Google Drive operation: ${data.operation}`);
    }
  } catch (error) {
    this.logger.error('Google Drive execution error:', error);
    throw error;
  }
}

Quando você DEVE usar este Node?

Use GOOGLE DRIVE quando precisar gerenciar arquivos na nuvem:

Casos de uso:

  1. Backup de mídias: Salvar fotos/vídeos recebidos no WhatsApp
  2. Compartilhar documentos: Enviar link de arquivo armazenado
  3. Organizar por cliente: Criar pasta para cada cliente automaticamente
  4. Arquivo de propostas: Armazenar PDFs de propostas enviadas
  5. Catálogo de produtos: Manter imagens organizadas por categoria
  6. Documentos recebidos: Arquivar documentos enviados por clientes

Quando NÃO usar GOOGLE DRIVE:

  • Dados estruturados: Use GOOGLE SHEETS para tabelas
  • Pequenos textos: Use VARIABLE para dados temporários
  • Arquivos Microsoft: Use ONEDRIVE para ecosistema Office

Parâmetros Detalhados

operation (string, obrigatório)

O que é: Define qual operação será executada no Google Drive.

Valores possíveis: - upload: Fazer upload de arquivo - download: Baixar arquivo - list: Listar arquivos/pastas - delete: Deletar arquivo/pasta - createFolder: Criar nova pasta

accessToken (string, obrigatório)

O que é: Token de acesso OAuth2 do Google para autenticação.

Como obter: Configure OAuth2 no Google Cloud Console.

refreshToken (string, obrigatório)

O que é: Token de refresh OAuth2 para renovar access token.

fileName (string, obrigatório para upload)

O que é: Nome do arquivo a ser criado no Drive.

Flow completo para testar:

{
  "name": "Teste GOOGLE DRIVE - Upload",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "media_1",
      "type": "media",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Receber Imagem",
        "parameters": {
          "message": "Envie uma imagem:",
          "variable": "imagem",
          "mediaType": "image"
        }
      }
    },
    {
      "id": "drive_1",
      "type": "google_drive",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Upload no Drive",
        "parameters": {
          "operation": "upload",
          "fileName": "imagem_{{timestamp}}.jpg",
          "content": "{{imagem}}",
          "mimeType": "image/jpeg",
          "folderId": "pasta_imagens_id",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Imagem salva no Drive!\n\n🔗 {{drive_1.webViewLink}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "media_1" },
    { "source": "media_1", "target": "drive_1" },
    { "source": "drive_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

content (string, obrigatório para upload)

O que é: Conteúdo do arquivo em base64.

mimeType (string, obrigatório para upload)

O que é: Tipo MIME do arquivo.

Exemplos comuns: - image/jpeg - Imagens JPG - image/png - Imagens PNG - application/pdf - Documentos PDF - video/mp4 - Vídeos MP4 - audio/mpeg - Áudios MP3 - text/plain - Arquivos de texto

folderId (string, opcional)

O que é: ID da pasta onde o arquivo será salvo (padrão: root).

Como obter: Na URL da pasta: https://drive.google.com/drive/folders/[FOLDER_ID]

fileId (string, obrigatório para download/delete)

O que é: ID único do arquivo no Google Drive.

Flow completo para testar:

{
  "name": "Teste GOOGLE DRIVE - Download",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "ID do Arquivo",
        "parameters": {
          "message": "Digite o ID do arquivo:",
          "variable": "file_id"
        }
      }
    },
    {
      "id": "drive_1",
      "type": "google_drive",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Baixar Arquivo",
        "parameters": {
          "operation": "download",
          "fileId": "{{file_id}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Arquivo baixado!\n\nTipo: {{drive_1.mimeType}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 900, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "drive_1" },
    { "source": "drive_1", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

query (string, opcional para list)

O que é: Query de busca do Google Drive (formato: Drive API query).

Exemplos: - "name contains 'relatorio'" - Arquivos com "relatorio" no nome - "mimeType='image/jpeg'" - Apenas imagens JPG - "modifiedTime > '2025-01-01T00:00:00'" - Modificados após data

pageSize (number, opcional)

O que é: Número máximo de resultados a retornar (padrão: 100, máximo: 1000).

Parâmetros

Campo Tipo Obrigatório Descrição
operation string Sim upload, download, list, delete, createFolder
accessToken string Sim Token OAuth2 de acesso
refreshToken string Sim Token OAuth2 de refresh
fileName string Sim* Nome do arquivo (para upload)
content string Sim* Conteúdo em base64 (para upload)
mimeType string Sim* Tipo MIME (para upload)
folderId string Não ID da pasta (padrão: root)
fileId string Sim* ID do arquivo (para download, delete)
query string Não Query de busca (para list)
pageSize number Não Limite de resultados (padrão: 100)
folderName string Sim* Nome da pasta (para createFolder)
parentFolderId string Não ID da pasta pai (para createFolder)

*Obrigatório dependendo da operação

Exemplo 1: Backup de Documentos Recebidos

Objetivo: Salvar automaticamente documentos enviados por clientes no Drive.

JSON para Importar

{
  "name": "Backup Automático - Google Drive",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Solicitar Documento",
        "parameters": {
          "message": "📄 Por favor, envie seu documento (PDF, imagem ou vídeo):"
        }
      }
    },
    {
      "id": "media_1",
      "type": "media",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Receber Mídia",
        "parameters": {
          "message": "Aguardando documento...",
          "variable": "documento"
        }
      }
    },
    {
      "id": "drive_1",
      "type": "google_drive",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Salvar no Drive",
        "parameters": {
          "operation": "upload",
          "fileName": "{{contact_name}}_{{timestamp}}",
          "content": "{{documento}}",
          "mimeType": "{{documento_mime_type}}",
          "folderId": "documentos_clientes_folder_id",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Documento recebido e arquivado!\n\n📁 ID: {{drive_1.fileId}}\n🔗 Link: {{drive_1.webViewLink}}\n\nObrigado!"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "message_1" },
    { "source": "message_1", "target": "media_1" },
    { "source": "media_1", "target": "drive_1" },
    { "source": "drive_1", "target": "message_2" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📄 Por favor, envie seu documento (PDF, imagem ou vídeo):
Sistema: Aguardando documento...
Usuário: [envia PDF]
Sistema: ✅ Documento recebido e arquivado!

📁 ID: 1abc2def3ghi
🔗 Link: https://drive.google.com/file/d/1abc2def3ghi/view

Obrigado!

Exemplo 2: Criar Estrutura de Pastas por Cliente

Objetivo: Criar pasta personalizada para cada novo cliente.

JSON para Importar

{
  "name": "Criar Pasta Cliente - Google Drive",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Nome do Cliente",
        "parameters": {
          "message": "Nome do novo cliente:",
          "variable": "cliente_nome"
        }
      }
    },
    {
      "id": "drive_1",
      "type": "google_drive",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Criar Pasta Principal",
        "parameters": {
          "operation": "createFolder",
          "folderName": "Cliente - {{cliente_nome}}",
          "parentFolderId": "clientes_root_folder_id",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "drive_2",
      "type": "google_drive",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Subpasta Contratos",
        "parameters": {
          "operation": "createFolder",
          "folderName": "Contratos",
          "parentFolderId": "{{drive_1.folderId}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "drive_3",
      "type": "google_drive",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Subpasta Documentos",
        "parameters": {
          "operation": "createFolder",
          "folderName": "Documentos",
          "parentFolderId": "{{drive_1.folderId}}",
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 1100, "y": 100 },
      "data": {
        "label": "Confirmar",
        "parameters": {
          "message": "✅ Estrutura criada para {{cliente_nome}}!\n\n📁 Pasta principal: {{drive_1.webViewLink}}\n📂 Contratos: {{drive_2.folderId}}\n📂 Documentos: {{drive_3.folderId}}"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1300, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "input_1" },
    { "source": "input_1", "target": "drive_1" },
    { "source": "drive_1", "target": "drive_2" },
    { "source": "drive_2", "target": "drive_3" },
    { "source": "drive_3", "target": "message_1" },
    { "source": "message_1", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: Nome do novo cliente:
Usuário: Tech Solutions LTDA
Sistema: ✅ Estrutura criada para Tech Solutions LTDA!

📁 Pasta principal: https://drive.google.com/drive/folders/abc123
📂 Contratos: def456
📂 Documentos: ghi789

Exemplo 3: Listar Arquivos e Compartilhar

Objetivo: Listar arquivos de uma pasta e enviar links ao usuário.

JSON para Importar

{
  "name": "Catálogo de Arquivos - Google Drive",
  "nodes": [
    {
      "id": "start_1",
      "type": "start",
      "position": { "x": 100, "y": 100 },
      "data": { "label": "Início" }
    },
    {
      "id": "drive_1",
      "type": "google_drive",
      "position": { "x": 300, "y": 100 },
      "data": {
        "label": "Listar PDFs",
        "parameters": {
          "operation": "list",
          "folderId": "catalogo_folder_id",
          "query": "mimeType='application/pdf'",
          "pageSize": 10,
          "accessToken": "{{google_access_token}}",
          "refreshToken": "{{google_refresh_token}}"
        }
      }
    },
    {
      "id": "message_1",
      "type": "message",
      "position": { "x": 500, "y": 100 },
      "data": {
        "label": "Mostrar Catálogo",
        "parameters": {
          "message": "📚 CATÁLOGO DE DOCUMENTOS\n\nEncontramos {{drive_1.files.length}} arquivos disponíveis.\n\nDigite o número do arquivo desejado."
        }
      }
    },
    {
      "id": "input_1",
      "type": "input",
      "position": { "x": 700, "y": 100 },
      "data": {
        "label": "Escolher Arquivo",
        "parameters": {
          "message": "Número do arquivo:",
          "variable": "arquivo_numero"
        }
      }
    },
    {
      "id": "message_2",
      "type": "message",
      "position": { "x": 900, "y": 100 },
      "data": {
        "label": "Enviar Link",
        "parameters": {
          "message": "✅ Aqui está o link do arquivo {{arquivo_numero}}:\n\n🔗 [Link será gerado dinamicamente]"
        }
      }
    },
    {
      "id": "end_1",
      "type": "end",
      "position": { "x": 1100, "y": 100 },
      "data": { "label": "Fim" }
    }
  ],
  "edges": [
    { "source": "start_1", "target": "drive_1" },
    { "source": "drive_1", "target": "message_1" },
    { "source": "message_1", "target": "input_1" },
    { "source": "input_1", "target": "message_2" },
    { "source": "message_2", "target": "end_1" }
  ]
}

Saída esperada:

Sistema: 📚 CATÁLOGO DE DOCUMENTOS

Encontramos 8 arquivos disponíveis.

Digite o número do arquivo desejado.
Sistema: Número do arquivo:
Usuário: 3
Sistema: ✅ Aqui está o link do arquivo 3:

🔗 [Link será gerado dinamicamente]

Resposta do Node

Operação UPLOAD:

{
  "success": true,
  "fileId": "1abc2def3ghi4jkl5mno",
  "fileName": "documento.pdf",
  "webViewLink": "https://drive.google.com/file/d/1abc2def3ghi4jkl5mno/view",
  "webContentLink": "https://drive.google.com/uc?id=1abc2def3ghi4jkl5mno&export=download"
}

Operação DOWNLOAD:

{
  "success": true,
  "content": "base64_encoded_content_here...",
  "mimeType": "application/pdf"
}

Operação LIST:

{
  "success": true,
  "files": [
    {
      "id": "1abc2def",
      "name": "relatorio.pdf",
      "mimeType": "application/pdf",
      "size": "1048576",
      "modifiedTime": "2025-01-15T10:30:00.000Z",
      "webViewLink": "https://drive.google.com/file/d/1abc2def/view"
    }
  ]
}

Operação CREATE_FOLDER:

{
  "success": true,
  "folderId": "1xyz2abc3def",
  "folderName": "Nova Pasta",
  "webViewLink": "https://drive.google.com/drive/folders/1xyz2abc3def"
}

Boas Práticas

SIM: - Use nomes descritivos para arquivos e pastas - Organize em estrutura de pastas lógica - Valide mimeType antes de upload - Implemente tratamento de erros - Use query específica para listar (melhor performance)

NÃO: - Não faça upload de arquivos muito grandes (> 10MB) sem validação - Não exponha tokens em logs ou mensagens - Não delete arquivos sem confirmação - Não abuse de listagens sem filtro

Dicas

💡 Permissões: Configure compartilhamento adequado nas pastas do Drive

💡 Quota: Google Drive tem limites de armazenamento e API, monitore uso

💡 Backup: Mantenha backups importantes em múltiplos locais

💡 Organização: Use convenções de nomenclatura consistentes (cliente_data_tipo.ext)

💡 Integração: Combine com GOOGLE SHEETS para indexar arquivos enviados

Próximo Node

ONEDRIVE - Alternativa Microsoft para armazenamento → GOOGLE SHEETS - Planilhas do Google → MEDIA - Receber mídias do WhatsApp