From 7f38d168219825199914f183cd3baddd3d0dd3c3 Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Mon, 30 Mar 2026 21:27:31 -0300 Subject: [PATCH] SSH: adiciona consulta usuario Juniper Signed-off-by: Rodrigo Bertoldo de Sousa Martins --- src/bot/handler.js | 52 ++++++++++++++++++++++++++++++- src/nlp/processor.js | 28 ++++++++++++++++- src/ssh/manager.js | 73 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/src/bot/handler.js b/src/bot/handler.js index 1c3389a..27097d4 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -139,6 +139,11 @@ class BotHandler { await this.handleListUsers(chatId, target); break; + case 'consultar_usuario': + console.log(`šŸ” Executando handleConsultarUsuario com target: ${target}`); + await this.handleConsultarUsuario(chatId, target); + break; + case 'admin': case 'administracao': await this.handleAdmin(chatId); @@ -331,6 +336,7 @@ Digite /help para ver todos os comandos disponĆ­veis! • "remover onu SERIAL" ļæ½ **JUNIPER:** +• "consultar usuario USER" • "desconectar cliente USER" • "listar usuĆ”rios conectados" @@ -463,7 +469,12 @@ Digite /help para ver todos os comandos disponĆ­veis! case 'juniper': helpMessage = `šŸ‘„ **JUNIPER - GERENCIAR USUƁRIOS** -**🚫 DESCONECTAR:** +**ļæ½ CONSULTAR USUƁRIO:** +• "consultar usuario USUARIO" +• "ver usuario USUARIO" +• "status usuario USUARIO" + +**�🚫 DESCONECTAR:** • "desconectar cliente USUARIO" • "kick usuĆ”rio USUARIO" • "remover cliente USUARIO" @@ -821,6 +832,45 @@ Digite /help para ver todos os comandos disponĆ­veis! } } + /** + * Consultar status de um assinante especĆ­fico no concentrador Juniper + */ + async handleConsultarUsuario(chatId, username) { + if (!username) { + await this.bot.sendMessage(chatId, 'ā“ Especifique o login do usuĆ”rio. Exemplo: "consultar usuario joao@provedor"'); + return; + } + + await this.bot.sendMessage(chatId, `šŸ” Consultando usuĆ”rio *${username}* no concentrador...`, { parse_mode: 'Markdown' }); + + try { + const result = await this.ssh.getJuniperSubscriberInfo('juniper', username); + + if (!result.success) { + await this.bot.sendMessage(chatId, `āŒ ${result.message}`); + return; + } + + if (!result.connected) { + await this.bot.sendMessage(chatId, `šŸ”“ *${username}* nĆ£o estĆ” conectado no concentrador.`, { parse_mode: 'Markdown' }); + return; + } + + const message = + `āœ… *UsuĆ”rio conectado!*\n\n` + + `šŸ‘¤ *Login:* \`${result.username}\`\n` + + `🌐 *EndereƧo IP:* \`${result.ip || 'N/A'}\`\n` + + `šŸ”Œ *Interface PPPoE:* \`${result.interface || 'N/A'}\`\n` + + `\nšŸ“‹ *Linha bruta:*\n\`\`\`\n${result.rawLine}\n\`\`\``; + + await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' }); + + } catch (error) { + console.error('Erro ao consultar usuĆ”rio:', error); + await this.bot.sendMessage(chatId, `āŒ Erro interno: ${error.message}`); + } + } + /** * Verificar sinal de ONU */ diff --git a/src/nlp/processor.js b/src/nlp/processor.js index 1187c5b..8b6e56f 100644 --- a/src/nlp/processor.js +++ b/src/nlp/processor.js @@ -31,7 +31,8 @@ class NLPProcessor { 'fiberhome_status': ['fiberhome status', 'status fiberhome', 'conexƵes fiberhome', 'fiberhome conexoes', 'fiberhome conectado'], 'dados_cliente': ['dados cliente', 'dados cadastrais', 'cadastro cliente', 'informaƧƵes cliente', 'info cliente', 'perfil cliente', 'ficha cliente', 'registro cliente', 'ver dados'], 'listar_servicos': ['listar serviƧos', 'servicos cliente', 'planos cliente', 'contratos cliente', 'ver servicos', 'plano cliente', 'assinaturas', 'planos', 'serviƧos ativos', 'ver plano'], - 'abrir_suporte': ['abrir suporte', 'criar suporte', 'adicionar suporte', 'novo suporte', 'suporte', 'chamado', 'ticket', 'atendimento', 'suporte tecnico', 'atendimento tecnico', 'abrir chamado', 'registrar chamado', 'criar chamado', 'visita tecnica', 'agendar visita', 'reclamação', 'reclamacao'] + 'abrir_suporte': ['abrir suporte', 'criar suporte', 'adicionar suporte', 'novo suporte', 'suporte', 'chamado', 'ticket', 'atendimento', 'suporte tecnico', 'atendimento tecnico', 'abrir chamado', 'registrar chamado', 'criar chamado', 'visita tecnica', 'agendar visita', 'reclamação', 'reclamacao'], + 'consultar_usuario': ['consultar usuario', 'consultar user', 'ver usuario', 'status usuario', 'status user', 'info usuario', 'info user', 'checar usuario', 'verificar usuario', 'pesquisar usuario', 'localizar usuario', 'buscar usuario', 'usuario conectado', 'user conectado', 'usuario online', 'user online', 'usuario ativo', 'user ativo'] }; // PadrƵes de comandos @@ -77,6 +78,9 @@ class NLPProcessor { /^(desconectar|kick|expulsar|remover)\s+(.+)\s+(do|no)?\s*(concentrador|juniper)?$/i, // PadrĆ£o genĆ©rico para desconectar (detectar se Ć© nome de usuĆ”rio) /^(desconectar|kick|expulsar|remover)\s+([a-zA-Z0-9_.-]+)$/i, + // PadrƵes para consultar usuĆ”rio especĆ­fico + /^(consultar|ver|status|info|checar|verificar|pesquisar|localizar|buscar)\s+(usuario|user)\s+(.+)$/i, + /^(usuario|user)\s+(.+)$/i, // PadrƵes para listar usuĆ”rios /^(listar|mostrar)\s+(usuĆ”rios|usuarios|clientes|users)(\s+conectados)?$/i, // PadrƵes gerais (devem vir por Ćŗltimo) @@ -229,6 +233,28 @@ class NLPProcessor { }; } + // Detectar consulta de usuĆ”rio especĆ­fico no Juniper + if (/consultar|ver|status|info|checar|verificar|pesquisar|localizar|buscar/i.test(action) && /usuario|user/i.test(fullMatch)) { + let username = match[3] || match[2]; + return { + action: 'consultar_usuario', + target: username ? username.trim() : null, + confidence: 0.95, + type: 'consultar_usuario_pattern' + }; + } + + // Detectar "usuario NOME" / "user NOME" + if (/^usuario$|^user$/i.test(action)) { + let username = match[2]; + return { + action: 'consultar_usuario', + target: username ? username.trim() : null, + confidence: 0.9, + type: 'consultar_usuario_simple' + }; + } + // Detectar comandos de suporte if (/abrir|criar|adicionar|novo|suporte|chamado|ticket|atendimento/i.test(action) && /suporte|chamado|ticket|atendimento/i.test(fullMatch)) { diff --git a/src/ssh/manager.js b/src/ssh/manager.js index 4427a66..24c30a5 100644 --- a/src/ssh/manager.js +++ b/src/ssh/manager.js @@ -395,6 +395,79 @@ class SSHManager { } } + /** + * Busca informaƧƵes de um assinante especĆ­fico no concentrador Juniper + * @param {string} equipmentId - ID do equipamento Juniper + * @param {string} username - Login do usuĆ”rio a pesquisar + * @returns {Promise} - Promise com status, IP e interface PPPoE do usuĆ”rio + */ + async getJuniperSubscriberInfo(equipmentId, username) { + try { + const connection = await this.connect(equipmentId); + + if (!connection.success) { + throw new Error(`Falha na conexĆ£o: ${connection.message}`); + } + + const command = `show subscribers terse | find ${username}`; + const result = await this.executeCommand(connection.connectionId, command); + + this.disconnect(connection.connectionId); + + if (!result.success && !result.output) { + return { + success: false, + connected: false, + message: `Erro ao consultar assinante: ${result.error}`, + username + }; + } + + // Procurar linha que contenha o username + const lines = result.output.split('\n'); + const userLine = lines.find(l => l.includes(username)); + + if (!userLine) { + return { + success: true, + connected: false, + message: `UsuĆ”rio ${username} nĆ£o estĆ” conectado`, + username, + ip: null, + interface: null + }; + } + + // Formato tĆ­pico da saĆ­da terse: + // pp0.1234 inet 203.0.113.5/32 user@dominio PPPoE + // Colunas: interface tipo endereƧo usuĆ”rio [estado] + const parts = userLine.trim().split(/\s+/); + const iface = parts[0] || null; + // EndereƧo IP fica na coluna que contĆ©m "/" + const ipField = parts.find(p => p.includes('/') || /^\d{1,3}(\.\d{1,3}){3}$/.test(p)); + const ip = ipField ? ipField.split('/')[0] : null; + + return { + success: true, + connected: true, + message: `UsuĆ”rio ${username} estĆ” conectado`, + username, + ip, + interface: iface, + rawLine: userLine.trim() + }; + + } catch (error) { + return { + success: false, + connected: false, + message: `Erro ao consultar assinante: ${error.message}`, + username, + error: error.message + }; + } + } + /** * Busca informaƧƵes de uma ONU pelo serial number na OLT * @param {string} equipmentId - ID do equipamento OLT