ваше сообщение коммита
This commit is contained in:
@@ -49,7 +49,6 @@ router.post('/task', requireAuth, async (req, res) => {
|
||||
|
||||
const taskData = {
|
||||
message,
|
||||
language: language || 'auto',
|
||||
history: history || null,
|
||||
systemPrompt: systemPrompt || '',
|
||||
rules: rules || null,
|
||||
|
||||
@@ -77,6 +77,7 @@ router.post('/read-dle-info', async (req, res) => {
|
||||
const blockchainData = {
|
||||
name: dleInfo.name,
|
||||
symbol: dleInfo.symbol,
|
||||
dleAddress: dleAddress, // Добавляем адрес контракта
|
||||
location: dleInfo.location,
|
||||
coordinates: dleInfo.coordinates,
|
||||
jurisdiction: Number(dleInfo.jurisdiction),
|
||||
@@ -400,6 +401,309 @@ router.post('/get-proposal-info', async (req, res) => {
|
||||
|
||||
|
||||
|
||||
// Проверка возможности деактивации DLE
|
||||
router.post('/deactivate-dle', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, userAddress } = req.body;
|
||||
|
||||
if (!dleAddress || !userAddress) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и адрес пользователя обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Проверка возможности деактивации DLE: ${dleAddress} пользователем: ${userAddress}`);
|
||||
|
||||
// Получаем RPC URL для Sepolia
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// ABI для проверки деактивации DLE
|
||||
const dleAbi = [
|
||||
"function isActive() external view returns (bool)",
|
||||
"function balanceOf(address) external view returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Проверяем, что пользователь имеет токены
|
||||
const balance = await dle.balanceOf(userAddress);
|
||||
if (balance <= 0) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: 'Для деактивации DLE необходимо иметь токены'
|
||||
});
|
||||
}
|
||||
|
||||
// Проверяем текущий статус
|
||||
const isActive = await dle.isActive();
|
||||
if (!isActive) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'DLE уже деактивирован'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] DLE ${dleAddress} может быть деактивирован пользователем ${userAddress}`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
dleAddress: dleAddress,
|
||||
canDeactivate: true,
|
||||
message: 'DLE может быть деактивирован при наличии валидного предложения с кворумом.'
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Blockchain] Ошибка при проверке возможности деактивации DLE:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при проверке возможности деактивации DLE: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Проверить результат предложения деактивации
|
||||
router.post('/check-deactivation-proposal-result', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId } = req.body;
|
||||
|
||||
if (!dleAddress || proposalId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE и ID предложения обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Проверка результата предложения деактивации: ${proposalId} для DLE: ${dleAddress}`);
|
||||
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function checkDeactivationProposalResult(uint256 _proposalId) public view returns (bool passed, bool quorumReached)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
const [passed, quorumReached] = await dle.checkDeactivationProposalResult(proposalId);
|
||||
|
||||
const result = {
|
||||
proposalId: proposalId,
|
||||
passed: passed,
|
||||
quorumReached: quorumReached,
|
||||
canExecute: passed && quorumReached
|
||||
};
|
||||
|
||||
console.log(`[Blockchain] Результат предложения деактивации:`, result);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: result
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Blockchain] Ошибка при проверке результата предложения деактивации:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при проверке результата предложения деактивации: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Загрузить предложения деактивации
|
||||
router.post('/load-deactivation-proposals', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress } = req.body;
|
||||
|
||||
if (!dleAddress) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Адрес DLE обязателен'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Загрузка предложений деактивации для DLE: ${dleAddress}`);
|
||||
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function deactivationProposalCounter() external view returns (uint256)",
|
||||
"function getDeactivationProposal(uint256 _proposalId) external view returns (uint256 id, string memory description, uint256 forVotes, uint256 againstVotes, bool executed, uint256 deadline, address initiator, uint256 chainId)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
const proposalCounter = await dle.deactivationProposalCounter();
|
||||
const proposals = [];
|
||||
|
||||
for (let i = 0; i < proposalCounter; i++) {
|
||||
try {
|
||||
const proposal = await dle.getDeactivationProposal(i);
|
||||
proposals.push({
|
||||
id: Number(proposal.id),
|
||||
description: proposal.description,
|
||||
forVotes: ethers.formatUnits(proposal.forVotes, 18),
|
||||
againstVotes: ethers.formatUnits(proposal.againstVotes, 18),
|
||||
executed: proposal.executed,
|
||||
deadline: Number(proposal.deadline),
|
||||
initiator: proposal.initiator,
|
||||
chainId: Number(proposal.chainId),
|
||||
isExpired: Date.now() / 1000 > Number(proposal.deadline)
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`[Blockchain] Ошибка при загрузке предложения ${i}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Загружено ${proposals.length} предложений деактивации`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
proposals: proposals
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Blockchain] Ошибка при загрузке предложений деактивации:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при загрузке предложений деактивации: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Создать предложение о добавлении модуля
|
||||
router.post('/create-add-module-proposal', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, description, duration, moduleId, moduleAddress, chainId } = req.body;
|
||||
|
||||
if (!dleAddress || !description || !duration || !moduleId || !moduleAddress || !chainId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Все поля обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Создание предложения о добавлении модуля: ${moduleId} для DLE: ${dleAddress}`);
|
||||
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function createAddModuleProposal(string memory _description, uint256 _duration, bytes32 _moduleId, address _moduleAddress, uint256 _chainId) external returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Создаем предложение
|
||||
const tx = await dle.createAddModuleProposal(description, duration, moduleId, moduleAddress, chainId);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
console.log(`[Blockchain] Предложение о добавлении модуля создано:`, receipt);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
proposalId: receipt.logs[0].args.proposalId,
|
||||
transactionHash: receipt.hash
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Blockchain] Ошибка при создании предложения о добавлении модуля:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при создании предложения о добавлении модуля: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Создать предложение об удалении модуля
|
||||
router.post('/create-remove-module-proposal', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, description, duration, moduleId, chainId } = req.body;
|
||||
|
||||
if (!dleAddress || !description || !duration || !moduleId || !chainId) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: 'Все поля обязательны'
|
||||
});
|
||||
}
|
||||
|
||||
console.log(`[Blockchain] Создание предложения об удалении модуля: ${moduleId} для DLE: ${dleAddress}`);
|
||||
|
||||
const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
|
||||
if (!rpcUrl) {
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
error: 'RPC URL для Sepolia не найден'
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function createRemoveModuleProposal(string memory _description, uint256 _duration, bytes32 _moduleId, uint256 _chainId) external returns (uint256)"
|
||||
];
|
||||
|
||||
const dle = new ethers.Contract(dleAddress, dleAbi, provider);
|
||||
|
||||
// Создаем предложение
|
||||
const tx = await dle.createRemoveModuleProposal(description, duration, moduleId, chainId);
|
||||
const receipt = await tx.wait();
|
||||
|
||||
console.log(`[Blockchain] Предложение об удалении модуля создано:`, receipt);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
proposalId: receipt.logs[0].args.proposalId,
|
||||
transactionHash: receipt.hash
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[Blockchain] Ошибка при создании предложения об удалении модуля:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: 'Ошибка при создании предложения об удалении модуля: ' + error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Импортируем WebSocket функции из wsHub
|
||||
const { broadcastProposalCreated, broadcastProposalVoted, broadcastProposalExecuted } = require('../wsHub');
|
||||
|
||||
|
||||
@@ -171,12 +171,9 @@ async function processGuestMessages(userId, guestId) {
|
||||
role: msg.sender_type === 'user' ? 'user' : 'assistant',
|
||||
content: msg.content
|
||||
}));
|
||||
// Язык guestMessage.language или auto
|
||||
const detectedLanguage = guestMessage.language === 'auto' ? aiAssistant.detectLanguage(guestMessage.content) : guestMessage.language;
|
||||
logger.info('Getting AI response for guest message:', guestMessage.content);
|
||||
const aiResponseContent = await aiAssistant.getResponse(
|
||||
guestMessage.content,
|
||||
detectedLanguage,
|
||||
history,
|
||||
aiSettings ? aiSettings.system_prompt : '',
|
||||
rules ? rules.rules : null
|
||||
@@ -310,7 +307,7 @@ router.post('/guest-message', upload.array('attachments'), async (req, res) => {
|
||||
[
|
||||
guestId,
|
||||
messageContent, // Текст сообщения или NULL
|
||||
language || 'auto',
|
||||
'ru', // Устанавливаем русский язык по умолчанию
|
||||
attachmentFilename,
|
||||
attachmentMimetype,
|
||||
attachmentSize,
|
||||
@@ -511,7 +508,14 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
|
||||
if (aiSettings && aiSettings.rules_id) {
|
||||
rules = await aiAssistantRulesService.getRuleById(aiSettings.rules_id);
|
||||
}
|
||||
// --- RAG автоответ ---
|
||||
// --- RAG автоответ с поддержкой беседы ---
|
||||
// Пример работы:
|
||||
// 1. Пользователь: "Как подключить кошелек?"
|
||||
// RAG: находит точный ответ → возвращает его
|
||||
// 2. Пользователь: "А какие документы нужны?"
|
||||
// RAG: анализирует контекст предыдущего ответа → ищет информацию о документах
|
||||
// 3. Пользователь: "Сколько это займет времени?"
|
||||
// RAG: использует полный контекст беседы → дает уточненный ответ
|
||||
let ragTableId = null;
|
||||
if (aiSettings && aiSettings.selected_rag_tables) {
|
||||
ragTableId = Array.isArray(aiSettings.selected_rag_tables)
|
||||
@@ -520,11 +524,29 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
|
||||
}
|
||||
let ragResult = null;
|
||||
if (ragTableId) {
|
||||
const { ragAnswer, generateLLMResponse } = require('../services/ragService');
|
||||
const threshold = 0.3;
|
||||
logger.info(`[RAG] Запуск поиска по RAG: tableId=${ragTableId}, вопрос="${messageContent}", threshold=${threshold}`);
|
||||
const ragResult = await ragAnswer({ tableId: ragTableId, userQuestion: messageContent, threshold });
|
||||
const { ragAnswerWithConversation, generateLLMResponse } = require('../services/ragService');
|
||||
const threshold = 200; // Увеличиваем threshold для более широкого поиска
|
||||
|
||||
// Получаем историю беседы
|
||||
const historyResult = await db.getQuery()(
|
||||
'SELECT decrypt_text(sender_type_encrypted, $3) as sender_type, decrypt_text(content_encrypted, $3) as content FROM messages WHERE conversation_id = $1 AND id < $2 ORDER BY created_at DESC LIMIT 10',
|
||||
[conversationId, userMessage.id, encryptionKey]
|
||||
);
|
||||
const history = historyResult.rows.reverse().map(msg => ({
|
||||
role: msg.sender_type === 'user' ? 'user' : 'assistant',
|
||||
content: msg.content
|
||||
}));
|
||||
|
||||
logger.info(`[RAG] Запуск поиска по RAG с беседой: tableId=${ragTableId}, вопрос="${messageContent}", threshold=${threshold}, historyLength=${history.length}`);
|
||||
const ragResult = await ragAnswerWithConversation({
|
||||
tableId: ragTableId,
|
||||
userQuestion: messageContent,
|
||||
threshold,
|
||||
history,
|
||||
conversationId
|
||||
});
|
||||
logger.info(`[RAG] Результат поиска по RAG:`, ragResult);
|
||||
logger.info(`[RAG] Score type: ${typeof ragResult.score}, value: ${ragResult.score}, threshold: ${threshold}, isFollowUp: ${ragResult.isFollowUp}`);
|
||||
if (ragResult && ragResult.answer && typeof ragResult.score === 'number' && Math.abs(ragResult.score) <= threshold) {
|
||||
logger.info(`[RAG] Найден confident-ответ (score=${ragResult.score}), отправляем ответ из базы.`);
|
||||
// Прямой ответ из RAG
|
||||
@@ -542,15 +564,7 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
|
||||
broadcastChatMessage(aiMessage);
|
||||
} else if (ragResult) {
|
||||
logger.info(`[RAG] Нет confident-ответа (score=${ragResult.score}), переходим к генерации через LLM.`);
|
||||
// Генерация через LLM с подстановкой значений из RAG
|
||||
const historyResult = await db.getQuery()(
|
||||
'SELECT decrypt_text(sender_type_encrypted, $3) as sender_type, decrypt_text(content_encrypted, $3) as content FROM messages WHERE conversation_id = $1 AND id < $2 ORDER BY created_at DESC LIMIT 10',
|
||||
[conversationId, userMessage.id, encryptionKey]
|
||||
);
|
||||
const history = historyResult.rows.reverse().map(msg => ({
|
||||
role: msg.sender_type === 'user' ? 'user' : 'assistant',
|
||||
content: msg.content
|
||||
}));
|
||||
// Генерация через LLM с подстановкой значений из RAG и историей беседы
|
||||
const llmResponse = await generateLLMResponse({
|
||||
userQuestion: messageContent,
|
||||
context: ragResult.context,
|
||||
@@ -558,9 +572,8 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
|
||||
clarifyingAnswer: ragResult.clarifyingAnswer,
|
||||
objectionAnswer: ragResult.objectionAnswer,
|
||||
systemPrompt: aiSettings ? aiSettings.system_prompt : '',
|
||||
history,
|
||||
model: aiSettings ? aiSettings.model : undefined,
|
||||
language: aiSettings && aiSettings.languages && aiSettings.languages.length > 0 ? aiSettings.languages[0] : 'ru'
|
||||
history: ragResult.conversationContext ? ragResult.conversationContext.conversationHistory : history,
|
||||
model: aiSettings ? aiSettings.model : undefined
|
||||
});
|
||||
if (llmResponse) {
|
||||
aiMessage = await encryptedDb.saveData('messages', {
|
||||
@@ -824,7 +837,6 @@ router.post('/message-queued', requireAuth, upload.array('attachments'), async (
|
||||
// Добавляем задачу в очередь
|
||||
const taskData = {
|
||||
message: messageContent,
|
||||
language: language || 'auto',
|
||||
history: history,
|
||||
systemPrompt: aiSettings ? aiSettings.system_prompt : '',
|
||||
rules: rules,
|
||||
@@ -927,7 +939,10 @@ router.get('/history', requireAuth, async (req, res) => {
|
||||
whereConditions.conversation_id = conversationId;
|
||||
}
|
||||
|
||||
const messages = await encryptedDb.getData('messages', whereConditions, limit, 'created_at ASC', offset);
|
||||
// Изменяем логику: загружаем ПОСЛЕДНИЕ сообщения, а не с offset
|
||||
const messages = await encryptedDb.getData('messages', whereConditions, limit, 'created_at DESC', 0);
|
||||
// Переворачиваем массив для правильного порядка
|
||||
messages.reverse();
|
||||
|
||||
// Обрабатываем результаты для фронтенда
|
||||
const formattedMessages = messages.map(msg => {
|
||||
@@ -1057,7 +1072,6 @@ router.post('/ai-draft', requireAuth, async (req, res) => {
|
||||
logger.info(`[RAG] [DRAFT] Результат поиска по RAG:`, ragResult);
|
||||
}
|
||||
const { generateLLMResponse } = require('../services/ragService');
|
||||
const detectedLanguage = language === 'auto' ? aiAssistant.detectLanguage(promptText) : language;
|
||||
const aiResponseContent = await generateLLMResponse({
|
||||
userQuestion: promptText,
|
||||
context: ragResult && ragResult.context ? ragResult.context : '',
|
||||
@@ -1065,7 +1079,6 @@ router.post('/ai-draft', requireAuth, async (req, res) => {
|
||||
systemPrompt: aiSettings ? aiSettings.system_prompt : '',
|
||||
history,
|
||||
model: aiSettings ? aiSettings.model : undefined,
|
||||
language: aiSettings && aiSettings.languages && aiSettings.languages.length > 0 ? aiSettings.languages[0] : 'ru',
|
||||
rules: rules ? rules.rules : null
|
||||
});
|
||||
res.json({ success: true, aiMessage: aiResponseContent });
|
||||
|
||||
@@ -27,6 +27,7 @@ const telegramBot = require('../services/telegramBot');
|
||||
const EmailBotService = require('../services/emailBot');
|
||||
const emailBotService = new EmailBotService();
|
||||
const dbSettingsService = require('../services/dbSettingsService');
|
||||
const { broadcastAuthTokenAdded, broadcastAuthTokenDeleted, broadcastAuthTokenUpdated } = require('../wsHub');
|
||||
|
||||
// Логируем версию ethers для отладки
|
||||
logger.info(`Ethers version: ${ethers.version || 'unknown'}`);
|
||||
@@ -163,6 +164,16 @@ router.post('/auth-tokens', requireAdmin, async (req, res, next) => {
|
||||
return res.status(400).json({ success: false, error: 'Неверный формат данных' });
|
||||
}
|
||||
await authTokenService.saveAllAuthTokens(authTokens);
|
||||
|
||||
// После сохранения токенов перепроверяем баланс ВСЕХ авторизованных пользователей
|
||||
const authService = require('../services/auth-service');
|
||||
try {
|
||||
await authService.recheckAllUsersAdminStatus();
|
||||
logger.info('Балансы всех пользователей перепроверены после сохранения токенов');
|
||||
} catch (balanceError) {
|
||||
logger.error(`Ошибка при перепроверке балансов всех пользователей: ${balanceError.message}`);
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Токены аутентификации успешно сохранены' });
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при сохранении токенов аутентификации:', error);
|
||||
@@ -178,6 +189,24 @@ router.post('/auth-token', requireAdmin, async (req, res, next) => {
|
||||
return res.status(400).json({ success: false, error: 'name, address и network обязательны' });
|
||||
}
|
||||
await authTokenService.upsertAuthToken({ name, address, network, minBalance });
|
||||
|
||||
// Отправляем WebSocket уведомление о добавлении токена
|
||||
try {
|
||||
broadcastAuthTokenAdded({ name, address, network, minBalance });
|
||||
logger.info('WebSocket уведомление о добавлении токена отправлено');
|
||||
} catch (wsError) {
|
||||
logger.error(`Ошибка при отправке WebSocket уведомления: ${wsError.message}`);
|
||||
}
|
||||
|
||||
// После добавления токена перепроверяем баланс ВСЕХ авторизованных пользователей
|
||||
const authService = require('../services/auth-service');
|
||||
try {
|
||||
await authService.recheckAllUsersAdminStatus();
|
||||
logger.info('Балансы всех пользователей перепроверены после добавления токена');
|
||||
} catch (balanceError) {
|
||||
logger.error(`Ошибка при перепроверке балансов всех пользователей: ${balanceError.message}`);
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Токен аутентификации сохранён' });
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при сохранении токена аутентификации:', error);
|
||||
@@ -190,6 +219,24 @@ router.delete('/auth-token/:address/:network', requireAdmin, async (req, res, ne
|
||||
try {
|
||||
const { address, network } = req.params;
|
||||
await authTokenService.deleteAuthToken(address, network);
|
||||
|
||||
// Отправляем WebSocket уведомление об удалении токена
|
||||
try {
|
||||
broadcastAuthTokenDeleted({ address, network });
|
||||
logger.info('WebSocket уведомление об удалении токена отправлено');
|
||||
} catch (wsError) {
|
||||
logger.error(`Ошибка при отправке WebSocket уведомления: ${wsError.message}`);
|
||||
}
|
||||
|
||||
// После удаления токена перепроверяем баланс ВСЕХ авторизованных пользователей
|
||||
const authService = require('../services/auth-service');
|
||||
try {
|
||||
await authService.recheckAllUsersAdminStatus();
|
||||
logger.info('Балансы всех пользователей перепроверены после удаления токена');
|
||||
} catch (balanceError) {
|
||||
logger.error(`Ошибка при перепроверке балансов всех пользователей: ${balanceError.message}`);
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Токен аутентификации удалён' });
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при удалении токена аутентификации:', error);
|
||||
|
||||
Reference in New Issue
Block a user