base: implementa guarai e pedro afonso

Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo@MacBook-Air-de-Rodrigo.local>
This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-06-19 11:39:13 -03:00
1 parent 44775d671f
commit bb32aebfc9
6 files changed
+375 -92

No files matched your search

+24
View File
@@ -8,8 +8,32 @@ DEFAULT_SSH_PASSWORD=password
# Configurações do bot # Configurações do bot
BOT_DEBUG=true BOT_DEBUG=true
# IDs do Telegram com acesso a TODAS as cidades/provedores (admin)
ALLOWED_USERS=123456789,987654321 ALLOWED_USERS=123456789,987654321
# ==========================================================
# Acesso por cidade/provedor (IDs do Telegram, separados por vírgula)
# Um usuário pode estar em mais de uma lista; se estiver em mais de
# uma cidade, o bot exibirá um menu para escolher qual atender.
# ==========================================================
GUARAI_ALLOWED_USERS=
PEDRO_AFONSO_ALLOWED_USERS=
# ==========================================================
# Concentrador Juniper - Guaraí
# ==========================================================
JUNIPER_GUARAI_HOST=131.0.192.254
JUNIPER_GUARAI_USER=rodrigo
JUNIPER_GUARAI_PASS=
# ==========================================================
# Concentrador Juniper - Pedro Afonso
# ==========================================================
JUNIPER_PEDRO_AFONSO_HOST=45.189.140.2
JUNIPER_PEDRO_AFONSO_USER=rodrigo
JUNIPER_PEDRO_AFONSO_PASS=
# Configurações TopSapp - Instância Guarai/Colmeia # Configurações TopSapp - Instância Guarai/Colmeia
TOPSAPP_GUARAI_USER=seu_usuario_guarai TOPSAPP_GUARAI_USER=seu_usuario_guarai
TOPSAPP_GUARAI_PASS=sua_senha_guarai TOPSAPP_GUARAI_PASS=sua_senha_guarai
+31 -1
View File
@@ -15,10 +15,40 @@ DEFAULT_SSH_PASSWORD=YOUR_SSH_PASSWORD_HERE
BOT_DEBUG=false BOT_DEBUG=false
NODE_ENV=production NODE_ENV=production
# IDs dos usuários autorizados (separados por vírgula) # IDs dos usuários autorizados em TODAS as cidades/provedores (admin)
# Para descobrir seu ID, envie /start para @userinfobot # Para descobrir seu ID, envie /start para @userinfobot
ALLOWED_USERS=593272271 ALLOWED_USERS=593272271
# IDs autorizados por cidade/provedor (deixe vazio se só ALLOWED_USERS for usado)
GUARAI_ALLOWED_USERS=
PEDRO_AFONSO_ALLOWED_USERS=
# ==========================================================
# Concentrador Juniper - Guaraí
# ==========================================================
JUNIPER_GUARAI_HOST=131.0.192.254
JUNIPER_GUARAI_USER=rodrigo
JUNIPER_GUARAI_PASS=@102030Rod
# ==========================================================
# Concentrador Juniper - Pedro Afonso
# ==========================================================
JUNIPER_PEDRO_AFONSO_HOST=45.189.140.2
JUNIPER_PEDRO_AFONSO_USER=rodrigo
JUNIPER_PEDRO_AFONSO_PASS=2311@Goiania#2017
# ==========================================================
# Configurações TopSapp - Instância Guaraí/Colmeia
# ==========================================================
TOPSAPP_GUARAI_USER=
TOPSAPP_GUARAI_PASS=
# ==========================================================
# Configurações TopSapp - Instância Pedro Afonso
# ==========================================================
TOPSAPP_PEDRO_AFONSO_USER=rodrigo
TOPSAPP_PEDRO_AFONSO_PASS=34641747
# ========================================================== # ==========================================================
# Configurações GenieACS (TR-069 ACS) # Configurações GenieACS (TR-069 ACS)
# ========================================================== # ==========================================================
+192 -48
View File
@@ -5,6 +5,7 @@ const FiberhomeManager = require('../fiberhome/manager');
const FiberhomeTL1Manager = require('../fiberhome/manager_tl1'); const FiberhomeTL1Manager = require('../fiberhome/manager_tl1');
const { GenieACSManager } = require('../genieacs'); const { GenieACSManager } = require('../genieacs');
const config = require('../config/config'); const config = require('../config/config');
const sites = require('../config/sites');
const logger = require('../utils/logger'); const logger = require('../utils/logger');
const DateProcessor = require('../utils/dateProcessor'); const DateProcessor = require('../utils/dateProcessor');
const cgnatParser = require('../cgn_list/parser'); const cgnatParser = require('../cgn_list/parser');
@@ -23,19 +24,89 @@ class BotHandler {
this.suporteSessions = new Map(); // Armazena sessões de suporte em andamento this.suporteSessions = new Map(); // Armazena sessões de suporte em andamento
this.pendingRestarts = new Map(); // Armazena dados de reinicialização pendentes this.pendingRestarts = new Map(); // Armazena dados de reinicialização pendentes
this._restartIdCounter = 0; this._restartIdCounter = 0;
this.activeSite = new Map(); // chatId -> siteId (cidade/provedor ativo)
logger.info('BotHandler inicializado'); logger.info('BotHandler inicializado');
console.log('🎯 BotHandler inicializado'); console.log('🎯 BotHandler inicializado');
} }
/** /**
* Verifica se o usuário tem permissão * Verifica se o usuário tem permissão (em pelo menos uma cidade/provedor)
*/ */
isAuthorized(userId) { isAuthorized(userId) {
if (config.bot.allowedUsers.length === 0) { return sites.getUserSiteIds(userId).length > 0;
return true; // Se não há lista de usuários, permite todos
} }
return config.bot.allowedUsers.includes(userId);
/**
* Cidade/provedor ativo para este chat. Pode ser null se ainda não
* foi resolvido (usuário com acesso a mais de um site e que ainda não
* escolheu via menu).
*/
getActiveSiteId(chatId) {
return this.activeSite.get(chatId) || null;
}
/**
* Site (objeto completo) ativo para este chat, com fallback seguro
* para Guaraí caso ainda não haja site resolvido (mantém o
* comportamento histórico do bot, que sempre assumiu Guaraí).
*/
getActiveSite(chatId) {
return sites.getSite(this.getActiveSiteId(chatId)) || sites.getSite('guarai');
}
/**
* Label de localização usado pelas heurísticas existentes do TopSapp
* (substitui a antiga detecção por regex no texto da mensagem).
*/
getActiveLocation(chatId) {
return this.getActiveSite(chatId).topsappLocationLabel;
}
/**
* Garante que o usuário tenha uma cidade/provedor ativa antes de
* processar qualquer ação. Se o usuário tiver acesso a mais de um
* site e ainda não tiver escolhido, exibe o menu de seleção e
* retorna null (o chamador deve interromper o processamento).
*/
async resolveActiveSite(chatId, userId) {
const siteIds = sites.getUserSiteIds(userId);
if (siteIds.length === 0) {
return null;
}
if (siteIds.length === 1) {
this.activeSite.set(chatId, siteIds[0]);
return siteIds[0];
}
const current = this.activeSite.get(chatId);
if (current && siteIds.includes(current)) {
return current;
}
await this.sendSiteSelectionMenu(chatId, siteIds);
return null;
}
/**
* Exibe o menu de seleção de cidade/provedor
*/
async sendSiteSelectionMenu(chatId, siteIds) {
const keyboard = siteIds.map(id => {
const site = sites.getSite(id);
return [{ text: `📍 ${site.name}`, callback_data: `select_site_${site.id}` }];
});
await this.bot.sendMessage(chatId,
`🏙️ *Selecione a cidade/provedor*\n\n` +
`Você tem acesso a mais de uma cidade. Escolha qual deseja atender agora:`,
{
parse_mode: 'Markdown',
reply_markup: { inline_keyboard: keyboard }
}
);
} }
/** /**
@@ -64,6 +135,12 @@ class BotHandler {
return; return;
} }
// Resolver cidade/provedor ativo (exibe menu se houver mais de um e ainda não escolhido)
const siteId = await this.resolveActiveSite(chatId, userId);
if (!siteId) {
return;
}
try { try {
// Verificar se há uma sessão de suporte ativa // Verificar se há uma sessão de suporte ativa
const processouSuporte = await this.processarMensagemSuporte(msg); const processouSuporte = await this.processarMensagemSuporte(msg);
@@ -124,7 +201,11 @@ class BotHandler {
break; break;
case 'help': case 'help':
await this.handleHelp(chatId); await this.handleHelp(chatId, userId);
break;
case 'cidade':
await this.handleCidade(chatId, userId);
break; break;
case 'ssh': case 'ssh':
@@ -352,12 +433,30 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, welcomeMessage, { parse_mode: 'Markdown' }); await this.bot.sendMessage(chatId, welcomeMessage, { parse_mode: 'Markdown' });
} }
/**
* Comando /cidade - permite trocar a cidade/provedor ativo
*/
async handleCidade(chatId, userId) {
const siteIds = sites.getUserSiteIds(userId);
if (siteIds.length <= 1) {
const site = sites.getSite(siteIds[0]) || this.getActiveSite(chatId);
await this.bot.sendMessage(chatId, `📍 Você só tem acesso a *${site.name}*.`, { parse_mode: 'Markdown' });
return;
}
await this.sendSiteSelectionMenu(chatId, siteIds);
}
/** /**
* Comando /help * Comando /help
*/ */
async handleHelp(chatId) { async handleHelp(chatId, userId = null) {
const siteName = this.getActiveSite(chatId).name;
const helpMessage = `🤖 **BOT DE AJUDA TÉCNICA** const helpMessage = `🤖 **BOT DE AJUDA TÉCNICA**
📍 Cidade/provedor ativo: *${siteName}*
🔧 **COMANDOS PRINCIPAIS:** 🔧 **COMANDOS PRINCIPAIS:**
• /start - Inicia o bot • /start - Inicia o bot
• /help - Esta ajuda • /help - Esta ajuda
@@ -409,6 +508,11 @@ Digite /help para ver todos os comandos disponíveis!
] ]
]; ];
if (userId && sites.getUserSiteIds(userId).length > 1) {
keyboard.push([{ text: '🏙️ Trocar cidade', callback_data: 'open_site_menu' }]);
}
await this.bot.sendMessage(chatId, helpMessage, { await this.bot.sendMessage(chatId, helpMessage, {
parse_mode: 'Markdown', parse_mode: 'Markdown',
reply_markup: { reply_markup: {
@@ -431,7 +535,7 @@ Digite /help para ver todos os comandos disponíveis!
switch (helpType) { switch (helpType) {
case 'main': case 'main':
await this.handleHelp(chatId); await this.handleHelp(chatId, callbackQuery.from.id);
return; return;
case 'topsapp': case 'topsapp':
@@ -657,7 +761,7 @@ Digite /help para ver todos os comandos disponíveis!
* Listar equipamentos * Listar equipamentos
*/ */
async handleListEquipments(chatId) { async handleListEquipments(chatId) {
const equipments = this.ssh.listEquipments(); const equipments = this.ssh.listEquipments(this.getActiveSite(chatId).id);
if (equipments.length === 0) { if (equipments.length === 0) {
await this.bot.sendMessage(chatId, '📋 Nenhum equipamento configurado.'); await this.bot.sendMessage(chatId, '📋 Nenhum equipamento configurado.');
@@ -830,8 +934,8 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, `🔄 Desconectando usuário ${username} do concentrador...`); await this.bot.sendMessage(chatId, `🔄 Desconectando usuário ${username} do concentrador...`);
try { try {
// Usar concentrador Juniper como padrão const juniperId = this.getActiveSite(chatId).juniperEquipmentId;
const result = await this.ssh.disconnectJuniperUser('juniper', username); const result = await this.ssh.disconnectJuniperUser(juniperId, username);
if (result.success) { if (result.success) {
await this.bot.sendMessage(chatId, `✅ ${result.message}`); await this.bot.sendMessage(chatId, `✅ ${result.message}`);
@@ -857,11 +961,12 @@ Digite /help para ver todos os comandos disponíveis!
/** /**
* Listar usuários conectados no concentrador * Listar usuários conectados no concentrador
*/ */
async handleListUsers(chatId, target = 'juniper') { async handleListUsers(chatId) {
await this.bot.sendMessage(chatId, '🔍 Listando usuários conectados no concentrador...'); await this.bot.sendMessage(chatId, '🔍 Listando usuários conectados no concentrador...');
try { try {
const result = await this.ssh.listJuniperUsers(target); const juniperId = this.getActiveSite(chatId).juniperEquipmentId;
const result = await this.ssh.listJuniperUsers(juniperId);
if (result.success) { if (result.success) {
let message = '📋 *Usuários Conectados:*\n\n'; let message = '📋 *Usuários Conectados:*\n\n';
@@ -926,7 +1031,8 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, `🔍 Consultando usuário *${username}* no concentrador...`, { parse_mode: 'Markdown' }); await this.bot.sendMessage(chatId, `🔍 Consultando usuário *${username}* no concentrador...`, { parse_mode: 'Markdown' });
try { try {
const result = await this.ssh.getJuniperSubscriberInfo('juniper', username); const juniperId = this.getActiveSite(chatId).juniperEquipmentId;
const result = await this.ssh.getJuniperSubscriberInfo(juniperId, username);
if (!result.success) { if (!result.success) {
await this.bot.sendMessage(chatId, `❌ ${result.message}`); await this.bot.sendMessage(chatId, `❌ ${result.message}`);
@@ -972,7 +1078,7 @@ Digite /help para ver todos os comandos disponíveis!
try { try {
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
let location = ''; let location = this.getActiveLocation(chatId);
let searchQuery = query; let searchQuery = query;
if (/guarai|colmeia/i.test(query)) { if (/guarai|colmeia/i.test(query)) {
@@ -1128,13 +1234,15 @@ Digite /help para ver todos os comandos disponíveis!
// Executar consultas em paralelo: Juniper + ONU + GenieACS (por TAG/login) // Executar consultas em paralelo: Juniper + ONU + GenieACS (por TAG/login)
// No concentrador Juniper usa-se só o usuário (antes do @) // No concentrador Juniper usa-se só o usuário (antes do @)
const activeSite = this.getActiveSite(chatId);
const juniperId = activeSite.juniperEquipmentId;
const pppoeUser = pppoeLogin ? pppoeLogin.split('@')[0] : null; const pppoeUser = pppoeLogin ? pppoeLogin.split('@')[0] : null;
let [juniperResult, onuResult, genieResult] = await Promise.all([ let [juniperResult, onuResult, genieResult] = await Promise.all([
pppoeUser pppoeUser
? this.ssh.getJuniperSubscriberInfo('juniper', pppoeUser).catch(e => ({ success: false, error: e.message })) ? this.ssh.getJuniperSubscriberInfo(juniperId, pppoeUser).catch(e => ({ success: false, error: e.message }))
: Promise.resolve({ success: false, skipped: true }), : Promise.resolve({ success: false, skipped: true }),
serial serial
? this._diagnosticarONU(serial, baseInfo).catch(e => ({ success: false, error: e.message })) ? this._diagnosticarONU(serial, baseInfo, activeSite.id).catch(e => ({ success: false, error: e.message }))
: Promise.resolve({ success: false, skipped: true }), : Promise.resolve({ success: false, skipped: true }),
pppoeLogin && this.genieacs.isReady() pppoeLogin && this.genieacs.isReady()
? this.genieacs.buscarRoteador(pppoeLogin).catch(() => ({ success: false })) ? this.genieacs.buscarRoteador(pppoeLogin).catch(() => ({ success: false }))
@@ -1144,7 +1252,7 @@ Digite /help para ver todos os comandos disponíveis!
// Fallback: se PPPoE não encontrou sessão ativa e há circuit-id (IPoE), buscar pelo circuit-id // Fallback: se PPPoE não encontrou sessão ativa e há circuit-id (IPoE), buscar pelo circuit-id
if (circuitId && (!juniperResult.connected)) { if (circuitId && (!juniperResult.connected)) {
try { try {
const circuitResult = await this.ssh.getJuniperSubscriberInfo('juniper', circuitId); const circuitResult = await this.ssh.getJuniperSubscriberInfo(juniperId, circuitId);
if (circuitResult.success && circuitResult.connected) { if (circuitResult.success && circuitResult.connected) {
juniperResult = { ...circuitResult, viaCircuitId: true }; juniperResult = { ...circuitResult, viaCircuitId: true };
} }
@@ -1286,11 +1394,13 @@ Digite /help para ver todos os comandos disponíveis!
/** /**
* Mapeia o campo base/AP do TopSapp para o ID da OLT Datacom (ou 'fiberhome') * Mapeia o campo base/AP do TopSapp para o ID da OLT Datacom (ou 'fiberhome')
* As bases DITO/COLMEIA/CANAA só existem em Guaraí; em outro site, ignora a dica.
*/ */
_resolverOLTporBase(baseInfo) { _resolverOLTporBase(baseInfo, siteId = 'guarai') {
if (!baseInfo) return null; if (!baseInfo) return null;
const b = String(baseInfo).toUpperCase(); const b = String(baseInfo).toUpperCase();
if (/INTERNET\s+FIBRA\s+OPTICA/i.test(b)) return 'fiberhome'; if (/INTERNET\s+FIBRA\s+OPTICA/i.test(b)) return 'fiberhome';
if (siteId !== 'guarai') return null;
if (/COLMEIA/i.test(b)) return 'olt_colmeia'; if (/COLMEIA/i.test(b)) return 'olt_colmeia';
if (/DITO/i.test(b)) return 'olt_dito'; if (/DITO/i.test(b)) return 'olt_dito';
if (/CANAA\s*2/i.test(b)) return 'olt_canaa2'; if (/CANAA\s*2/i.test(b)) return 'olt_canaa2';
@@ -1302,10 +1412,11 @@ Digite /help para ver todos os comandos disponíveis!
* Diagnóstico de ONU: detecta tipo (Datacom/FiberHome) e retorna dados estruturados * Diagnóstico de ONU: detecta tipo (Datacom/FiberHome) e retorna dados estruturados
* @param {string} serial - Serial da ONU * @param {string} serial - Serial da ONU
* @param {string|null} baseInfo - Campo base/AP do TopSapp para rotear para OLT correta * @param {string|null} baseInfo - Campo base/AP do TopSapp para rotear para OLT correta
* @param {string} siteId - Cidade/provedor ativo, usado para restringir a busca
*/ */
async _diagnosticarONU(serial, baseInfo) { async _diagnosticarONU(serial, baseInfo, siteId = 'guarai') {
const serialUpper = serial.toUpperCase(); const serialUpper = serial.toUpperCase();
const oltHint = this._resolverOLTporBase(baseInfo); const oltHint = this._resolverOLTporBase(baseInfo, siteId);
// Usar base description para decidir se é FiberHome // Usar base description para decidir se é FiberHome
if (oltHint === 'fiberhome' || if (oltHint === 'fiberhome' ||
@@ -1313,10 +1424,10 @@ Digite /help para ver todos os comandos disponíveis!
return await this._diagnosticarONUFiberhome(serial); return await this._diagnosticarONUFiberhome(serial);
} }
return await this._diagnosticarONUDatacom(serial, oltHint); return await this._diagnosticarONUDatacom(serial, oltHint, siteId);
} }
async _diagnosticarONUDatacom(serial, oltIdHint) { async _diagnosticarONUDatacom(serial, oltIdHint, siteId = 'guarai') {
let found = null; let found = null;
// 1. Tentar na OLT indicada pelo campo base/AP do cadastro // 1. Tentar na OLT indicada pelo campo base/AP do cadastro
@@ -1328,9 +1439,9 @@ Digite /help para ver todos os comandos disponíveis!
} }
} }
// 2. Fallback: buscar em todas as OLTs Datacom // 2. Fallback: buscar em todas as OLTs Datacom do site ativo
if (!found) { if (!found) {
const olts = this.ssh.listOLTs(); const olts = this.ssh.listOLTs(siteId);
if (olts.length === 0) { if (olts.length === 0) {
return { success: false, error: 'Nenhuma OLT Datacom configurada' }; return { success: false, error: 'Nenhuma OLT Datacom configurada' };
} }
@@ -1445,8 +1556,9 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
// Obter lista de OLTs disponíveis // Obter lista de OLTs disponíveis no site ativo
const olts = this.ssh.listOLTs(); const activeSiteId = this.getActiveSite(chatId).id;
const olts = this.ssh.listOLTs(activeSiteId);
console.log(`📋 OLTs Datacom encontradas: ${olts.length}`); console.log(`📋 OLTs Datacom encontradas: ${olts.length}`);
// Criar menu de seleção de OLT // Criar menu de seleção de OLT
@@ -1454,10 +1566,12 @@ Digite /help para ver todos os comandos disponíveis!
inline_keyboard: [] inline_keyboard: []
}; };
// Adicionar OLT Fiberhome como primeira opção // Adicionar OLT Fiberhome como primeira opção (existe apenas em Guaraí)
if (activeSiteId === 'guarai') {
keyboard.inline_keyboard.push([ keyboard.inline_keyboard.push([
{ text: '🔶 OLT FIBERHOME', callback_data: `check_signal_fiberhome_${serialNumber}` } { text: '🔶 OLT FIBERHOME', callback_data: `check_signal_fiberhome_${serialNumber}` }
]); ]);
}
// Adicionar separador visual // Adicionar separador visual
if (olts.length > 0) { if (olts.length > 0) {
@@ -1579,8 +1693,8 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
// Perguntar em qual OLT buscar // Perguntar em qual OLT buscar (apenas OLTs do site ativo)
const oltOptions = this.ssh.listOLTs(); const oltOptions = this.ssh.listOLTs(this.getActiveSite(chatId).id);
if (oltOptions.length === 0) { if (oltOptions.length === 0) {
await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.'); await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.');
@@ -1620,8 +1734,8 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
// Perguntar em qual OLT adicionar // Perguntar em qual OLT adicionar (apenas OLTs do site ativo)
const oltOptions = this.ssh.listOLTs(); const oltOptions = this.ssh.listOLTs(this.getActiveSite(chatId).id);
if (oltOptions.length === 0) { if (oltOptions.length === 0) {
await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.'); await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.');
@@ -1666,8 +1780,8 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
// Perguntar em qual OLT adicionar // Perguntar em qual OLT adicionar (apenas OLTs do site ativo)
const oltOptions = this.ssh.listOLTs(); const oltOptions = this.ssh.listOLTs(this.getActiveSite(chatId).id);
if (oltOptions.length === 0) { if (oltOptions.length === 0) {
await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.'); await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.');
@@ -2004,6 +2118,35 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
// Seleção/troca de cidade — tratado antes de resolver o site ativo,
// pois é a própria ação que define o site ativo.
if (data.startsWith('select_site_')) {
const siteId = data.replace('select_site_', '');
const site = sites.getSite(siteId);
if (!site || !sites.getUserSiteIds(userId).includes(siteId)) {
await this.bot.answerCallbackQuery(callbackQuery.id, '🚫 Cidade inválida');
return;
}
this.activeSite.set(chatId, siteId);
await this.bot.answerCallbackQuery(callbackQuery.id, `📍 ${site.name}`);
await this.bot.sendMessage(chatId, `📍 Cidade/provedor definido: *${site.name}*`, { parse_mode: 'Markdown' });
await this.handleHelp(chatId, userId);
return;
}
if (data === 'open_site_menu') {
await this.bot.answerCallbackQuery(callbackQuery.id);
await this.sendSiteSelectionMenu(chatId, sites.getUserSiteIds(userId));
return;
}
// Garante que haja uma cidade/provedor ativa antes de qualquer outra ação
const activeSiteId = await this.resolveActiveSite(chatId, userId);
if (!activeSiteId) {
await this.bot.answerCallbackQuery(callbackQuery.id);
return;
}
try { try {
console.log(`🔍 Callback recebido: ${data}`); console.log(`🔍 Callback recebido: ${data}`);
console.log(`🔍 Verifica confirm_remove_: ${data.startsWith('confirm_remove_')}`); console.log(`🔍 Verifica confirm_remove_: ${data.startsWith('confirm_remove_')}`);
@@ -4250,7 +4393,7 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
// Detectar se especificou uma localização // Detectar se especificou uma localização
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -4386,7 +4529,7 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
// Detectar se especificou uma localização // Detectar se especificou uma localização
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -4496,7 +4639,7 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
// Detectar se especificou uma localização // Detectar se especificou uma localização
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -4617,7 +4760,7 @@ Digite /help para ver todos os comandos disponíveis!
await this.bot.sendMessage(chatId, '🔍 Buscando serviços...'); await this.bot.sendMessage(chatId, '🔍 Buscando serviços...');
// Detectar se especificou uma localização // Detectar se especificou uma localização
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -4994,7 +5137,7 @@ Digite /help para ver todos os comandos disponíveis!
try { try {
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -5723,7 +5866,7 @@ Digite /help para ver todos os comandos disponíveis!
try { try {
// Primeiro, buscar o cliente // Primeiro, buscar o cliente
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) { if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
@@ -6859,7 +7002,7 @@ Digite /help para ver todos os comandos disponíveis!
} }
session.dados.clienteSelecionado = session.dados.clientesEncontrados[numero - 1]; session.dados.clienteSelecionado = session.dados.clientesEncontrados[numero - 1];
session.dados.location = ''; session.dados.location = this.getActiveLocation(session.chatId);
await this.processarEtapaFecharBuscarSuportes(sessionId); await this.processarEtapaFecharBuscarSuportes(sessionId);
} }
@@ -7519,7 +7662,7 @@ Digite /help para ver todos os comandos disponíveis!
} }
session.dados.clienteSelecionado = clientes[index]; session.dados.clienteSelecionado = clientes[index];
session.dados.location = ''; session.dados.location = this.getActiveLocation(chatId);
await this.processarEtapaFecharBuscarSuportes(sessionId); await this.processarEtapaFecharBuscarSuportes(sessionId);
} }
@@ -8232,7 +8375,7 @@ Digite /help para ver todos os comandos disponíveis!
try { try {
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
let location = ''; let location = this.getActiveLocation(chatId);
let query = target; let query = target;
if (/guarai|colmeia/i.test(target)) { if (/guarai|colmeia/i.test(target)) {
@@ -8601,7 +8744,7 @@ Digite /help para ver todos os comandos disponíveis!
try { try {
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
let location = ''; let location = this.getActiveLocation(chatId);
let searchQuery = query; let searchQuery = query;
if (/guarai|colmeia/i.test(query)) { if (/guarai|colmeia/i.test(query)) {
@@ -8721,7 +8864,7 @@ Digite /help para ver todos os comandos disponíveis!
return; return;
} }
const oltHint = this._resolverOLTporBase(base); const oltHint = this._resolverOLTporBase(base, this.getActiveSite(chatId).id);
const tipoOLT = oltHint === 'fiberhome' ? '🔶 Fiberhome (TL1)' : '🔷 Datacom (SSH)'; const tipoOLT = oltHint === 'fiberhome' ? '🔶 Fiberhome (TL1)' : '🔷 Datacom (SSH)';
const serialEscaped = serial.replace(/_/g, '\\_'); const serialEscaped = serial.replace(/_/g, '\\_');
@@ -8812,7 +8955,8 @@ Digite /help para ver todos os comandos disponíveis!
this.pendingRestarts.delete(restartId); this.pendingRestarts.delete(restartId);
const { serial, base } = pending; const { serial, base } = pending;
const oltHint = this._resolverOLTporBase(base); const siteId = this.getActiveSite(chatId).id;
const oltHint = this._resolverOLTporBase(base, siteId);
const serialEscaped = serial.replace(/_/g, '\\_'); const serialEscaped = serial.replace(/_/g, '\\_');
await this.bot.editMessageText( await this.bot.editMessageText(
@@ -8839,7 +8983,7 @@ Digite /help para ver todos os comandos disponíveis!
// Sem base definida — tentar Fiberhome primeiro, depois Datacom // Sem base definida — tentar Fiberhome primeiro, depois Datacom
result = await this.fiberhomeTL1.reiniciarOnu(serial); result = await this.fiberhomeTL1.reiniciarOnu(serial);
if (!result.success) { if (!result.success) {
result = await this._reiniciarOnuDatacomAutoDetect(serial); result = await this._reiniciarOnuDatacomAutoDetect(serial, siteId);
} }
} }
@@ -9176,8 +9320,8 @@ Digite /help para ver todos os comandos disponíveis!
/** /**
* Reiniciar ONU Datacom — busca em todas as OLTs * Reiniciar ONU Datacom — busca em todas as OLTs
*/ */
async _reiniciarOnuDatacomAutoDetect(serial) { async _reiniciarOnuDatacomAutoDetect(serial, siteId = 'guarai') {
const olts = this.ssh.listOLTs(); const olts = this.ssh.listOLTs(siteId);
for (const olt of olts) { for (const olt of olts) {
try { try {
const findResult = await this.ssh.findOnuBySerial(olt.id, serial); const findResult = await this.ssh.findOnuBySerial(olt.id, serial);
+78
View File
@@ -0,0 +1,78 @@
/**
* Registro central de sites (cidades/provedores) atendidos pelo bot.
* Para adicionar uma nova cidade: acrescente um objeto aqui e configure a
* variável de ambiente correspondente (allowedUsersEnv) — nenhum outro
* módulo precisa saber quantos sites existem.
*/
const SITES = [
{
id: 'guarai',
name: 'Guaraí',
allowedUsersEnv: 'GUARAI_ALLOWED_USERS',
topsappKey: 'guarai_colmeia',
topsappLocationLabel: 'Guarai/Colmeia',
juniperEquipmentId: 'juniper',
oltEquipmentIds: ['olt_dito', 'olt_colmeia', 'olt_canaa', 'olt_canaa2']
},
{
id: 'pedro_afonso',
name: 'Pedro Afonso',
allowedUsersEnv: 'PEDRO_AFONSO_ALLOWED_USERS',
topsappKey: 'pedro_afonso',
topsappLocationLabel: 'Pedro Afonso',
juniperEquipmentId: 'juniper_pedro_afonso',
oltEquipmentIds: ['olt_pedro_afonso', 'olt_canavieiras']
}
];
function parseUserIds(envValue) {
if (!envValue) return [];
return envValue.split(',').map(id => parseInt(id.trim(), 10)).filter(id => !isNaN(id));
}
function getAllSites() {
return SITES;
}
function getSite(id) {
return SITES.find(site => site.id === id) || null;
}
/**
* Retorna os ids dos sites aos quais o usuário do Telegram tem acesso.
* - Quem está em ALLOWED_USERS (config global) tem acesso a todos os sites.
* - Caso contrário, cada site é liberado se o userId estiver na env var
* `site.allowedUsersEnv` correspondente.
* - Se nenhuma das variáveis (global ou por site) estiver configurada,
* mantém o comportamento histórico de "sem lista = libera todo mundo",
* liberando acesso a todos os sites.
*/
function getUserSiteIds(userId) {
const config = require('./config');
const globalUsers = config.bot.allowedUsers;
if (globalUsers.length > 0 && globalUsers.includes(userId)) {
return SITES.map(site => site.id);
}
const siteAllowLists = SITES.map(site => parseUserIds(process.env[site.allowedUsersEnv]));
const anyPerSiteListConfigured = siteAllowLists.some(list => list.length > 0);
if (globalUsers.length === 0 && !anyPerSiteListConfigured) {
return SITES.map(site => site.id);
}
const result = [];
SITES.forEach((site, index) => {
if (siteAllowLists[index].includes(userId)) {
result.push(site.id);
}
});
return result;
}
module.exports = {
getAllSites,
getSite,
getUserSiteIds
};
+40 -43
View File
@@ -22,51 +22,41 @@ class SSHManager {
}); });
} }
// Concentrador Juniper principal // Concentrador Juniper - Guaraí
this.equipamentos.set('juniper', { const juniperGuarai = {
name: 'Concentrador Juniper', name: 'Concentrador Juniper',
host: '131.0.192.254', host: process.env.JUNIPER_GUARAI_HOST || '131.0.192.254',
username: 'rodrigo', username: process.env.JUNIPER_GUARAI_USER || 'rodrigo',
password: '@102030Rod', password: process.env.JUNIPER_GUARAI_PASS || '',
port: 22, port: 22,
type: 'juniper' type: 'juniper',
}); site: 'guarai'
};
this.equipamentos.set('juniper', juniperGuarai);
this.equipamentos.set('concentrador', juniperGuarai); // alias
// Aliases para o concentrador // Concentrador Juniper - Pedro Afonso
this.equipamentos.set('concentrador', { const juniperPedroAfonso = {
name: 'Concentrador Juniper', name: 'Concentrador Juniper Pedro Afonso',
host: '131.0.192.254', host: process.env.JUNIPER_PEDRO_AFONSO_HOST || '45.189.140.2',
username: 'rodrigo', username: process.env.JUNIPER_PEDRO_AFONSO_USER || 'rodrigo',
password: '@102030Rod', password: process.env.JUNIPER_PEDRO_AFONSO_PASS || '',
port: 22, port: 22,
type: 'juniper' type: 'juniper',
}); site: 'pedro_afonso'
};
this.equipamentos.set('juniper_pedro_afonso', juniperPedroAfonso);
this.equipamentos.set('concentrador_pedro_afonso', juniperPedroAfonso); // alias
// Exemplos de equipamentos (você pode configurar mais) // OLTs Guaraí
this.equipamentos.set('router1', {
name: 'Router Principal',
host: '192.168.1.1',
username: 'admin',
password: 'admin',
port: 22
});
this.equipamentos.set('switch1', {
name: 'Switch Core',
host: '192.168.1.10',
username: 'admin',
password: 'admin',
port: 22
});
// OLTs para verificação de sinal
this.equipamentos.set('olt_dito', { this.equipamentos.set('olt_dito', {
name: 'OLT DITO', name: 'OLT DITO',
host: '192.168.190.7', host: '192.168.190.7',
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'guarai'
}); });
this.equipamentos.set('olt_colmeia', { this.equipamentos.set('olt_colmeia', {
@@ -75,7 +65,8 @@ class SSHManager {
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'guarai'
}); });
this.equipamentos.set('olt_canaa', { this.equipamentos.set('olt_canaa', {
@@ -84,7 +75,8 @@ class SSHManager {
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'guarai'
}); });
this.equipamentos.set('olt_canaa2', { this.equipamentos.set('olt_canaa2', {
@@ -93,16 +85,19 @@ class SSHManager {
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'guarai'
}); });
// OLTs Pedro Afonso
this.equipamentos.set('olt_pedro_afonso', { this.equipamentos.set('olt_pedro_afonso', {
name: 'OLT PEDRO AFONSO 1', name: 'OLT PEDRO AFONSO 1',
host: '192.168.100.2', host: '192.168.100.2',
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'pedro_afonso'
}); });
this.equipamentos.set('olt_canavieiras', { this.equipamentos.set('olt_canavieiras', {
@@ -111,7 +106,8 @@ class SSHManager {
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
port: 22, port: 22,
type: 'olt' type: 'olt',
site: 'pedro_afonso'
}); });
} }
@@ -259,10 +255,11 @@ class SSHManager {
/** /**
* Lista equipamentos disponíveis * Lista equipamentos disponíveis
*/ */
listEquipments() { listEquipments(siteId = null) {
const equipments = []; const equipments = [];
for (const [id, equipment] of this.equipamentos) { for (const [id, equipment] of this.equipamentos) {
if (siteId && equipment.site !== siteId) continue;
equipments.push({ equipments.push({
id: id, id: id,
name: equipment.name, name: equipment.name,
@@ -696,11 +693,12 @@ class SSHManager {
* Lista todos os equipamentos OLT disponíveis * Lista todos os equipamentos OLT disponíveis
* @returns {Array} - Array com OLTs disponíveis * @returns {Array} - Array com OLTs disponíveis
*/ */
listOLTs() { listOLTs(siteId = null) {
const olts = []; const olts = [];
for (const [id, equipment] of this.equipamentos) { for (const [id, equipment] of this.equipamentos) {
if (equipment.type === 'olt') { if (equipment.type !== 'olt') continue;
if (siteId && equipment.site !== siteId) continue;
olts.push({ olts.push({
id: id, id: id,
name: equipment.name, name: equipment.name,
@@ -708,7 +706,6 @@ class SSHManager {
port: equipment.port || 22 port: equipment.port || 22
}); });
} }
}
return olts; return olts;
} }
+10
View File
@@ -48,6 +48,16 @@ class TopSappConfig {
return this.credentials[instanceKey] || null; return this.credentials[instanceKey] || null;
} }
/**
* Obter credenciais a partir do site ativo (cidade/provedor)
*/
getCredentialsBySite(siteId) {
const sites = require('../config/sites');
const site = sites.getSite(siteId);
if (!site) return this.credentials.guarai_colmeia;
return this.credentials[site.topsappKey] || null;
}
/** /**
* Obter credenciais por localização * Obter credenciais por localização
*/ */