591 lines
26 KiB
JavaScript
591 lines
26 KiB
JavaScript
/**
|
||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||
* All rights reserved.
|
||
*
|
||
* This software is proprietary and confidential.
|
||
* Unauthorized copying, modification, or distribution is prohibited.
|
||
*
|
||
* For licensing inquiries: info@hb3-accelerator.com
|
||
* Website: https://hb3-accelerator.com
|
||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||
*/
|
||
|
||
const { Telegraf } = require('telegraf');
|
||
const logger = require('../utils/logger');
|
||
const encryptedDb = require('./encryptedDatabaseService');
|
||
const db = require('../db');
|
||
const authService = require('./auth-service');
|
||
const verificationService = require('./verification-service');
|
||
const crypto = require('crypto');
|
||
const identityService = require('./identity-service');
|
||
const aiAssistant = require('./ai-assistant');
|
||
const { checkAdminRole } = require('./admin-role');
|
||
const { broadcastContactsUpdate, broadcastChatMessage } = require('../wsHub');
|
||
const aiAssistantSettingsService = require('./aiAssistantSettingsService');
|
||
const { ragAnswer, generateLLMResponse } = require('./ragService');
|
||
const { isUserBlocked } = require('../utils/userUtils');
|
||
|
||
let botInstance = null;
|
||
let telegramSettingsCache = null;
|
||
|
||
async function getTelegramSettings() {
|
||
if (telegramSettingsCache) return telegramSettingsCache;
|
||
|
||
const settings = await encryptedDb.getData('telegram_settings', {}, 1);
|
||
if (!settings.length) throw new Error('Telegram settings not found in DB');
|
||
|
||
telegramSettingsCache = settings[0];
|
||
return telegramSettingsCache;
|
||
}
|
||
|
||
// Создание и настройка бота
|
||
async function getBot() {
|
||
console.log('[TelegramBot] getBot() called');
|
||
if (!botInstance) {
|
||
console.log('[TelegramBot] Creating new bot instance...');
|
||
const settings = await getTelegramSettings();
|
||
console.log('[TelegramBot] Got settings, creating Telegraf instance...');
|
||
botInstance = new Telegraf(settings.bot_token);
|
||
console.log('[TelegramBot] Telegraf instance created');
|
||
|
||
// Обработка команды /start
|
||
botInstance.command('start', (ctx) => {
|
||
ctx.reply('Добро пожаловать! Отправьте код подтверждения для аутентификации.');
|
||
});
|
||
|
||
// Универсальный обработчик текстовых сообщений
|
||
botInstance.on('text', async (ctx) => {
|
||
const text = ctx.message.text.trim();
|
||
// 1. Если команда — пропустить
|
||
if (text.startsWith('/')) return;
|
||
|
||
// Отправляем индикатор печати для улучшения UX
|
||
const typingAction = ctx.replyWithChatAction('typing');
|
||
|
||
// 2. Проверка: это потенциальный код?
|
||
const isPotentialCode = (str) => /^[A-Z0-9]{6}$/i.test(str);
|
||
if (isPotentialCode(text)) {
|
||
await typingAction;
|
||
try {
|
||
// Получаем код верификации для всех активных кодов с провайдером telegram
|
||
const codes = await encryptedDb.getData('verification_codes', {
|
||
code: text.toUpperCase(),
|
||
provider: 'telegram',
|
||
used: false
|
||
}, 1);
|
||
|
||
if (codes.length === 0) {
|
||
ctx.reply('Неверный код подтверждения');
|
||
return;
|
||
}
|
||
|
||
const verification = codes[0];
|
||
const providerId = verification.provider_id;
|
||
const linkedUserId = verification.user_id; // Получаем связанный userId если он есть
|
||
let userId;
|
||
let userRole = 'user'; // Роль по умолчанию
|
||
|
||
// Отмечаем код как использованный
|
||
await encryptedDb.saveData('verification_codes', {
|
||
used: true
|
||
}, {
|
||
id: verification.id
|
||
});
|
||
|
||
logger.info('Starting Telegram auth process for code:', text);
|
||
|
||
// Проверяем, существует ли уже пользователь с таким Telegram ID
|
||
const existingTelegramUsers = await encryptedDb.getData('user_identities', {
|
||
provider: 'telegram',
|
||
provider_id: ctx.from.id.toString()
|
||
}, 1);
|
||
|
||
if (existingTelegramUsers.length > 0) {
|
||
// Если пользователь с таким Telegram ID уже существует, используем его
|
||
userId = existingTelegramUsers[0].user_id;
|
||
logger.info(`Using existing user ${userId} for Telegram account ${ctx.from.id}`);
|
||
} else {
|
||
// Если код верификации был связан с существующим пользователем, используем его
|
||
if (linkedUserId) {
|
||
// Используем userId из кода верификации
|
||
userId = linkedUserId;
|
||
// Связываем Telegram с этим пользователем
|
||
await encryptedDb.saveData('user_identities', {
|
||
user_id: userId,
|
||
provider: 'telegram',
|
||
provider_id: ctx.from.id.toString()
|
||
});
|
||
logger.info(
|
||
`Linked Telegram account ${ctx.from.id} to pre-authenticated user ${userId}`
|
||
);
|
||
} else {
|
||
// Проверяем, есть ли пользователь, связанный с гостевым идентификатором
|
||
let existingUserWithGuestId = null;
|
||
if (providerId) {
|
||
const guestUserResult = await encryptedDb.getData('guest_user_mapping', {
|
||
guest_id: providerId
|
||
}, 1);
|
||
if (guestUserResult.length > 0) {
|
||
existingUserWithGuestId = guestUserResult[0].user_id;
|
||
logger.info(
|
||
`Found existing user ${existingUserWithGuestId} by guest ID ${providerId}`
|
||
);
|
||
}
|
||
}
|
||
|
||
if (existingUserWithGuestId) {
|
||
// Используем существующего пользователя и добавляем ему Telegram идентификатор
|
||
userId = existingUserWithGuestId;
|
||
await encryptedDb.saveData('user_identities', {
|
||
user_id: userId,
|
||
provider: 'telegram',
|
||
provider_id: ctx.from.id.toString()
|
||
});
|
||
logger.info(`Linked Telegram account ${ctx.from.id} to existing user ${userId}`);
|
||
} else {
|
||
// Создаем нового пользователя, если не нашли существующего
|
||
const userResult = await encryptedDb.saveData('users', {
|
||
created_at: new Date(),
|
||
role: 'user'
|
||
});
|
||
userId = userResult.id;
|
||
|
||
// Связываем Telegram с новым пользователем
|
||
await encryptedDb.saveData('user_identities', {
|
||
user_id: userId,
|
||
provider: 'telegram',
|
||
provider_id: ctx.from.id.toString()
|
||
});
|
||
|
||
// Если был гостевой ID, связываем его с новым пользователем
|
||
if (providerId) {
|
||
await encryptedDb.saveData('guest_user_mapping', {
|
||
user_id: userId,
|
||
guest_id: providerId
|
||
}, {
|
||
user_id: userId
|
||
});
|
||
}
|
||
|
||
logger.info(`Created new user ${userId} with Telegram account ${ctx.from.id}`);
|
||
}
|
||
}
|
||
}
|
||
|
||
// ----> НАЧАЛО: Проверка роли на основе привязанного кошелька <----
|
||
if (userId) { // Убедимся, что userId определен
|
||
logger.info(`[TelegramBot] Checking linked wallet for determined userId: ${userId} (Type: ${typeof userId})`);
|
||
try {
|
||
const linkedWallet = await authService.getLinkedWallet(userId);
|
||
if (linkedWallet) {
|
||
logger.info(`[TelegramBot] Found linked wallet ${linkedWallet} for user ${userId}. Checking role...`);
|
||
const isAdmin = await checkAdminRole(linkedWallet);
|
||
userRole = isAdmin ? 'admin' : 'user';
|
||
logger.info(`[TelegramBot] Role for user ${userId} determined as: ${userRole}`);
|
||
|
||
// Опционально: Обновить роль в таблице users
|
||
const currentUser = await encryptedDb.getData('users', {
|
||
id: userId
|
||
}, 1);
|
||
if (currentUser.length > 0 && currentUser[0].role !== userRole) {
|
||
await encryptedDb.saveData('users', {
|
||
role: userRole
|
||
}, {
|
||
id: userId
|
||
});
|
||
logger.info(`[TelegramBot] Updated user role in DB to ${userRole}`);
|
||
}
|
||
} else {
|
||
logger.info(`[TelegramBot] No linked wallet found for user ${userId}. Checking current DB role.`);
|
||
// Если кошелька нет, берем текущую роль из базы
|
||
const currentUser = await encryptedDb.getData('users', {
|
||
id: userId
|
||
}, 1);
|
||
if (currentUser.length > 0) {
|
||
userRole = currentUser[0].role;
|
||
}
|
||
}
|
||
} catch (roleCheckError) {
|
||
logger.error(`[TelegramBot] Error checking admin role for user ${userId}:`, roleCheckError);
|
||
// В случае ошибки берем роль из базы или оставляем 'user'
|
||
try {
|
||
const currentUser = await encryptedDb.getData('users', {
|
||
id: userId
|
||
}, 1);
|
||
if (currentUser.length > 0) { userRole = currentUser[0].role; }
|
||
} catch (dbError) { /* ignore */ }
|
||
}
|
||
} else {
|
||
logger.error('[TelegramBot] Cannot check role because userId is undefined!');
|
||
}
|
||
// ----> КОНЕЦ: Проверка роли <----
|
||
|
||
// Логируем userId перед обновлением сессии
|
||
logger.info(`[telegramBot] Attempting to update session for userId: ${userId}`);
|
||
|
||
// Находим последнюю активную сессию для данного userId
|
||
let activeSessionId = null;
|
||
try {
|
||
// Ищем сессию, где есть userId и она не истекла (проверка expires_at)
|
||
// Сортируем по expires_at DESC чтобы взять самую "свежую", если их несколько
|
||
const sessionResult = await encryptedDb.getData('session', {
|
||
'sess->>userId': userId?.toString()
|
||
}, 1, 'expire', 'DESC');
|
||
|
||
if (sessionResult.length > 0) {
|
||
activeSessionId = sessionResult[0].sid;
|
||
logger.info(`[telegramBot] Found active session ID ${activeSessionId} for user ${userId}`);
|
||
|
||
// Обновляем найденную сессию в базе данных, добавляя/перезаписывая данные Telegram
|
||
const updateResult = await encryptedDb.saveData('session', {
|
||
sess: JSON.stringify({
|
||
// authenticated: true, // Не перезаписываем, т.к. сессия уже должна быть аутентифицирована
|
||
authType: 'telegram', // Обновляем тип аутентификации
|
||
telegramId: ctx.from.id.toString(),
|
||
telegramUsername: ctx.from.username,
|
||
telegramFirstName: ctx.from.first_name,
|
||
role: userRole, // Записываем определенную роль
|
||
// userId: userId?.toString() // userId уже должен быть в сессии
|
||
})
|
||
}, {
|
||
sid: activeSessionId
|
||
});
|
||
|
||
if (updateResult.rowCount > 0) {
|
||
logger.info(`[telegramBot] Session ${activeSessionId} updated successfully with Telegram data for user ${userId}`);
|
||
} else {
|
||
logger.warn(`[telegramBot] Session update query executed but did not update rows for sid: ${activeSessionId}. This might indicate a concurrency issue or incorrect sid.`);
|
||
}
|
||
|
||
} else {
|
||
logger.warn(`[telegramBot] No active web session found for userId: ${userId}. Telegram is linked, but the user might need to refresh their browser session.`);
|
||
}
|
||
} catch(sessionError) {
|
||
logger.error(`[telegramBot] Error finding or updating session for userId ${userId}:`, sessionError);
|
||
}
|
||
|
||
// Отправляем сообщение об успешной аутентификации
|
||
await ctx.reply('Аутентификация успешна! Можете вернуться в приложение.');
|
||
|
||
// Удаляем сообщение с кодом
|
||
try {
|
||
await ctx.deleteMessage(ctx.message.message_id);
|
||
} catch (error) {
|
||
logger.warn('Could not delete code message:', error);
|
||
}
|
||
|
||
// После каждого успешного создания пользователя:
|
||
broadcastContactsUpdate();
|
||
} catch (error) {
|
||
logger.error('Error in Telegram auth:', error);
|
||
await ctx.reply('Произошла ошибка при аутентификации. Попробуйте позже.');
|
||
}
|
||
return;
|
||
}
|
||
|
||
// 3. Всё остальное — чат с ИИ-ассистентом
|
||
try {
|
||
const telegramId = ctx.from.id.toString();
|
||
|
||
// 1. Найти или создать пользователя
|
||
const { userId, role } = await identityService.findOrCreateUserWithRole('telegram', telegramId);
|
||
if (await isUserBlocked(userId)) {
|
||
await ctx.reply('Вы заблокированы. Сообщения не принимаются.');
|
||
return;
|
||
}
|
||
|
||
// 1.1 Найти или создать беседу
|
||
let conversationResult = await encryptedDb.getData('conversations', {
|
||
user_id: userId
|
||
}, 1, 'updated_at', 'DESC', 'created_at', 'DESC');
|
||
let conversation;
|
||
if (conversationResult.length === 0) {
|
||
const title = `Чат с пользователем ${userId}`;
|
||
const newConv = await encryptedDb.saveData('conversations', {
|
||
user_id: userId,
|
||
title: title,
|
||
created_at: new Date(),
|
||
updated_at: new Date()
|
||
});
|
||
conversation = newConv;
|
||
} else {
|
||
conversation = conversationResult[0];
|
||
}
|
||
|
||
// 2. Сохранять все сообщения с conversation_id
|
||
let content = text;
|
||
let attachmentMeta = {};
|
||
// Проверяем вложения (фото, документ, аудио, видео)
|
||
let fileId, fileName, mimeType, fileSize, attachmentBuffer;
|
||
if (ctx.message.document) {
|
||
fileId = ctx.message.document.file_id;
|
||
fileName = ctx.message.document.file_name;
|
||
mimeType = ctx.message.document.mime_type;
|
||
fileSize = ctx.message.document.file_size;
|
||
} else if (ctx.message.photo && ctx.message.photo.length > 0) {
|
||
// Берём самое большое фото
|
||
const photo = ctx.message.photo[ctx.message.photo.length - 1];
|
||
fileId = photo.file_id;
|
||
fileName = 'photo.jpg';
|
||
mimeType = 'image/jpeg';
|
||
fileSize = photo.file_size;
|
||
} else if (ctx.message.audio) {
|
||
fileId = ctx.message.audio.file_id;
|
||
fileName = ctx.message.audio.file_name || 'audio.ogg';
|
||
mimeType = ctx.message.audio.mime_type || 'audio/ogg';
|
||
fileSize = ctx.message.audio.file_size;
|
||
} else if (ctx.message.video) {
|
||
fileId = ctx.message.video.file_id;
|
||
fileName = ctx.message.video.file_name || 'video.mp4';
|
||
mimeType = ctx.message.video.mime_type || 'video/mp4';
|
||
fileSize = ctx.message.video.file_size;
|
||
}
|
||
|
||
// Асинхронная загрузка файлов
|
||
if (fileId) {
|
||
try {
|
||
const fileLink = await ctx.telegram.getFileLink(fileId);
|
||
const res = await fetch(fileLink.href);
|
||
attachmentBuffer = await res.buffer();
|
||
attachmentMeta = {
|
||
attachment_filename: fileName,
|
||
attachment_mimetype: mimeType,
|
||
attachment_size: fileSize,
|
||
attachment_data: attachmentBuffer
|
||
};
|
||
} catch (fileError) {
|
||
logger.error('[TelegramBot] Error downloading file:', fileError);
|
||
// Продолжаем без файла
|
||
}
|
||
}
|
||
|
||
// Сохраняем сообщение в БД
|
||
if (!conversation || !conversation.id) {
|
||
logger.error(`[TelegramBot] Conversation is undefined or has no id for user ${userId}`);
|
||
await ctx.reply('Произошла ошибка при создании диалога. Попробуйте позже.');
|
||
return;
|
||
}
|
||
|
||
const userMessage = await encryptedDb.saveData('messages', {
|
||
user_id: userId,
|
||
conversation_id: conversation.id,
|
||
sender_type: 'user',
|
||
content: content,
|
||
channel: 'telegram',
|
||
role: role,
|
||
direction: 'in',
|
||
created_at: new Date(),
|
||
attachment_filename: attachmentMeta.attachment_filename || null,
|
||
attachment_mimetype: attachmentMeta.attachment_mimetype || null,
|
||
attachment_size: attachmentMeta.attachment_size || null,
|
||
attachment_data: attachmentMeta.attachment_data || null
|
||
});
|
||
|
||
// Отправляем WebSocket уведомление о пользовательском сообщении
|
||
try {
|
||
const decryptedUserMessage = await encryptedDb.getData('messages', { id: userMessage.id }, 1);
|
||
if (decryptedUserMessage && decryptedUserMessage[0]) {
|
||
broadcastChatMessage(decryptedUserMessage[0], userId);
|
||
}
|
||
} catch (wsError) {
|
||
logger.error('[TelegramBot] WebSocket notification error for user message:', wsError);
|
||
}
|
||
|
||
if (await isUserBlocked(userId)) {
|
||
logger.info(`[TelegramBot] Пользователь ${userId} заблокирован — ответ ИИ не отправляется.`);
|
||
return;
|
||
}
|
||
|
||
// 3. Получить ответ от ИИ (RAG + LLM) - асинхронно
|
||
const aiResponsePromise = (async () => {
|
||
const aiSettings = await aiAssistantSettingsService.getSettings();
|
||
let ragTableId = null;
|
||
if (aiSettings && aiSettings.selected_rag_tables) {
|
||
ragTableId = Array.isArray(aiSettings.selected_rag_tables)
|
||
? aiSettings.selected_rag_tables[0]
|
||
: aiSettings.selected_rag_tables;
|
||
}
|
||
|
||
// Загружаем историю сообщений для контекста (ограничиваем до 5 сообщений)
|
||
let history = null;
|
||
try {
|
||
const recentMessages = await encryptedDb.getData('messages', {
|
||
conversation_id: conversation.id
|
||
}, 5, 'created_at DESC');
|
||
|
||
if (recentMessages && recentMessages.length > 0) {
|
||
// Преобразуем сообщения в формат для AI
|
||
history = recentMessages.reverse().map(msg => ({
|
||
role: msg.sender_type === 'user' ? 'user' : 'assistant',
|
||
content: msg.content || '' // content уже расшифрован encryptedDb
|
||
}));
|
||
}
|
||
} catch (historyError) {
|
||
logger.error('[TelegramBot] Error loading message history:', historyError);
|
||
}
|
||
|
||
let aiResponse;
|
||
if (ragTableId) {
|
||
// Сначала ищем ответ через RAG
|
||
const ragResult = await ragAnswer({ tableId: ragTableId, userQuestion: content });
|
||
if (ragResult && ragResult.answer && typeof ragResult.score === 'number' && Math.abs(ragResult.score) <= 0.3) {
|
||
aiResponse = ragResult.answer;
|
||
} else {
|
||
aiResponse = await generateLLMResponse({
|
||
userQuestion: content,
|
||
context: ragResult && ragResult.context ? ragResult.context : '',
|
||
answer: ragResult && ragResult.answer ? ragResult.answer : '',
|
||
systemPrompt: aiSettings ? aiSettings.system_prompt : '',
|
||
history: history,
|
||
model: aiSettings ? aiSettings.model : undefined,
|
||
language: aiSettings && aiSettings.languages && aiSettings.languages.length > 0 ? aiSettings.languages[0] : 'ru'
|
||
});
|
||
}
|
||
} else {
|
||
// Используем системный промпт из настроек, если RAG не используется
|
||
const systemPrompt = aiSettings ? aiSettings.system_prompt : '';
|
||
aiResponse = await aiAssistant.getResponse(content, 'auto', history, systemPrompt);
|
||
}
|
||
|
||
return aiResponse;
|
||
})();
|
||
|
||
// Ждем ответ от ИИ с таймаутом
|
||
const aiResponse = await Promise.race([
|
||
aiResponsePromise,
|
||
new Promise((_, reject) =>
|
||
setTimeout(() => reject(new Error('AI response timeout')), 60000)
|
||
)
|
||
]);
|
||
|
||
// 4. Сохранить ответ в БД с conversation_id
|
||
const aiMessage = await encryptedDb.saveData('messages', {
|
||
user_id: userId,
|
||
conversation_id: conversation.id,
|
||
sender_type: 'assistant',
|
||
content: aiResponse,
|
||
channel: 'telegram',
|
||
role: role,
|
||
direction: 'out',
|
||
created_at: new Date()
|
||
});
|
||
|
||
// 5. Отправить ответ пользователю
|
||
await ctx.reply(aiResponse);
|
||
|
||
// 6. Отправить WebSocket уведомление
|
||
try {
|
||
const decryptedAiMessage = await encryptedDb.getData('messages', { id: aiMessage.id }, 1);
|
||
if (decryptedAiMessage && decryptedAiMessage[0]) {
|
||
broadcastChatMessage(decryptedAiMessage[0], userId);
|
||
}
|
||
} catch (wsError) {
|
||
logger.error('[TelegramBot] WebSocket notification error:', wsError);
|
||
}
|
||
} catch (error) {
|
||
logger.error('[TelegramBot] Ошибка при обработке сообщения:', error);
|
||
await ctx.reply('Произошла ошибка при обработке вашего сообщения. Попробуйте позже.');
|
||
}
|
||
});
|
||
|
||
// Запуск бота с таймаутом
|
||
console.log('[TelegramBot] Before botInstance.launch()');
|
||
try {
|
||
// Запускаем бота с таймаутом
|
||
const launchPromise = botInstance.launch();
|
||
const timeoutPromise = new Promise((_, reject) => {
|
||
setTimeout(() => reject(new Error('Telegram bot launch timeout')), 10000); // 10 секунд таймаут
|
||
});
|
||
|
||
await Promise.race([launchPromise, timeoutPromise]);
|
||
console.log('[TelegramBot] After botInstance.launch()');
|
||
logger.info('[TelegramBot] Бот запущен');
|
||
} catch (error) {
|
||
console.error('[TelegramBot] Error launching bot:', error);
|
||
// Не выбрасываем ошибку, чтобы не блокировать запуск сервера
|
||
console.log('[TelegramBot] Bot launch failed, but continuing...');
|
||
}
|
||
}
|
||
|
||
return botInstance;
|
||
}
|
||
|
||
// Остановка бота
|
||
async function stopBot() {
|
||
if (botInstance) {
|
||
try {
|
||
await botInstance.stop();
|
||
botInstance = null;
|
||
logger.info('Telegram bot stopped successfully');
|
||
} catch (error) {
|
||
logger.error('Error stopping Telegram bot:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Инициализация процесса аутентификации
|
||
async function initTelegramAuth(session) {
|
||
try {
|
||
// Используем временный идентификатор для создания кода верификации
|
||
// Реальный пользователь будет создан или найден при проверке кода через бота
|
||
const tempId = crypto.randomBytes(16).toString('hex');
|
||
|
||
// Если пользователь уже авторизован, сохраняем его userId в guest_user_mapping
|
||
// чтобы потом при авторизации через бота этот пользователь был найден
|
||
if (session && session.authenticated && session.userId) {
|
||
const guestId = session.guestId || tempId;
|
||
|
||
// Связываем гостевой ID с текущим пользователем
|
||
await encryptedDb.saveData('guest_user_mapping', {
|
||
user_id: session.userId,
|
||
guest_id: guestId
|
||
}, {
|
||
user_id: session.userId
|
||
});
|
||
|
||
logger.info(
|
||
`[initTelegramAuth] Linked guestId ${guestId} to authenticated user ${session.userId}`
|
||
);
|
||
}
|
||
|
||
// Создаем код через сервис верификации с идентификатором
|
||
const code = await verificationService.createVerificationCode(
|
||
'telegram',
|
||
session.guestId || tempId,
|
||
session.authenticated ? session.userId : null
|
||
);
|
||
|
||
logger.info(
|
||
`[initTelegramAuth] Created verification code for guestId: ${session.guestId || tempId}${session.authenticated ? `, userId: ${session.userId}` : ''}`
|
||
);
|
||
|
||
const settings = await getTelegramSettings();
|
||
return {
|
||
verificationCode: code,
|
||
botLink: `https://t.me/${settings.bot_username}`,
|
||
};
|
||
} catch (error) {
|
||
logger.error('Error initializing Telegram auth:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
function clearSettingsCache() {
|
||
telegramSettingsCache = null;
|
||
}
|
||
|
||
async function getAllBots() {
|
||
const settings = await encryptedDb.getData('telegram_settings', {}, 1, 'id');
|
||
return settings;
|
||
}
|
||
|
||
module.exports = {
|
||
getTelegramSettings,
|
||
getBot,
|
||
stopBot,
|
||
initTelegramAuth,
|
||
clearSettingsCache,
|
||
getAllBots,
|
||
};
|