ваше сообщение коммита

This commit is contained in:
2025-05-22 16:24:39 +03:00
parent a91658eb31
commit 9aa842d238
41 changed files with 1621 additions and 507 deletions

View File

@@ -6,49 +6,49 @@ const authService = require('../services/auth-service');
const logger = require('../utils/logger');
// Роли
router.get('/roles', requireAdmin, async (req, res) => {
router.get('/roles', requireAdmin, async (req, res, next) => {
try {
const roles = await authService.getAllRoles();
res.json({ success: true, roles });
} catch (error) {
logger.error('Error getting roles:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
router.post('/roles', requireAdmin, async (req, res) => {
router.post('/roles', requireAdmin, async (req, res, next) => {
try {
const { name, permissions } = req.body;
const role = await authService.createRole(name, permissions);
res.json({ success: true, role });
} catch (error) {
logger.error('Error creating role:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Админ функции
router.get('/users', requireAdmin, async (req, res) => {
router.get('/users', requireAdmin, async (req, res, next) => {
try {
const users = await authService.getAllUsers();
res.json({ success: true, users });
} catch (error) {
logger.error('Error getting users:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Маршрут для получения статистики (защищен middleware requireAdmin)
router.get('/stats', requireAdmin, async (req, res) => {
router.get('/stats', requireAdmin, async (req, res, next) => {
try {
// Получаем количество пользователей
const usersCount = await db.query('SELECT COUNT(*) FROM users');
const usersCount = await db.getQuery()('SELECT COUNT(*) FROM users');
// Получаем количество досок
const boardsCount = await db.query('SELECT COUNT(*) FROM kanban_boards');
const boardsCount = await db.getQuery()('SELECT COUNT(*) FROM kanban_boards');
// Получаем количество задач
const tasksCount = await db.query('SELECT COUNT(*) FROM kanban_tasks');
const tasksCount = await db.getQuery()('SELECT COUNT(*) FROM kanban_tasks');
res.json({
userCount: parseInt(usersCount.rows[0].count),
@@ -57,18 +57,18 @@ router.get('/stats', requireAdmin, async (req, res) => {
});
} catch (error) {
console.error('Ошибка при получении статистики:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Маршрут для получения логов
router.get('/logs', requireAdmin, async (req, res) => {
router.get('/logs', requireAdmin, async (req, res, next) => {
try {
const result = await db.query('SELECT * FROM logs ORDER BY created_at DESC LIMIT 100');
const result = await db.getQuery()('SELECT * FROM logs ORDER BY created_at DESC LIMIT 100');
res.json(result.rows);
} catch (error) {
console.error('Ошибка при получении логов:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});

View File

@@ -34,7 +34,7 @@ router.get('/nonce', async (req, res) => {
const nonce = crypto.randomBytes(16).toString('hex');
// Проверяем, существует ли уже nonce для этого адреса
const existingNonce = await db.query('SELECT id FROM nonces WHERE identity_value = $1', [
const existingNonce = await db.getQuery()('SELECT id FROM nonces WHERE identity_value = $1', [
address.toLowerCase(),
]);

View File

@@ -17,7 +17,7 @@ async function processGuestMessages(userId, guestId) {
logger.info(`Processing guest messages for user ${userId} with guest ID ${guestId}`);
// Проверяем, обрабатывались ли уже эти сообщения
const mappingCheck = await db.query(
const mappingCheck = await db.getQuery()(
'SELECT processed FROM guest_user_mapping WHERE guest_id = $1',
[guestId]
);
@@ -30,7 +30,7 @@ async function processGuestMessages(userId, guestId) {
// Проверяем наличие mapping записи и создаем если нет
if (mappingCheck.rows.length === 0) {
await db.query(
await db.getQuery()(
'INSERT INTO guest_user_mapping (user_id, guest_id) VALUES ($1, $2) ON CONFLICT (guest_id) DO UPDATE SET user_id = $1',
[userId, guestId]
);
@@ -38,7 +38,7 @@ async function processGuestMessages(userId, guestId) {
}
// Получаем все гостевые сообщения со всеми новыми полями
const guestMessagesResult = await db.query(
const guestMessagesResult = await db.getQuery()(
`SELECT
id, guest_id, content, language, is_ai, created_at,
attachment_filename, attachment_mimetype, attachment_size, attachment_data
@@ -48,9 +48,9 @@ async function processGuestMessages(userId, guestId) {
if (guestMessagesResult.rows.length === 0) {
logger.info(`No guest messages found for guest ID ${guestId}`);
const checkResult = await db.query('SELECT 1 FROM guest_user_mapping WHERE guest_id = $1', [guestId]);
const checkResult = await db.getQuery()('SELECT 1 FROM guest_user_mapping WHERE guest_id = $1', [guestId]);
if (checkResult.rows.length > 0) {
await db.query('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [guestId]);
await db.getQuery()('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [guestId]);
logger.info(`Marked guest mapping as processed (no messages found) for guest ID ${guestId}`);
} else {
logger.warn(`Attempted to mark non-existent guest mapping as processed for guest ID ${guestId}`);
@@ -67,7 +67,7 @@ async function processGuestMessages(userId, guestId) {
? (firstMessage.content.length > 30 ? `${firstMessage.content.substring(0, 30)}...` : firstMessage.content)
: (firstMessage.attachment_filename ? `Файл: ${firstMessage.attachment_filename}` : 'Новый диалог');
const newConversationResult = await db.query(
const newConversationResult = await db.getQuery()(
'INSERT INTO conversations (user_id, title) VALUES ($1, $2) RETURNING *',
[userId, title]
);
@@ -84,7 +84,7 @@ async function processGuestMessages(userId, guestId) {
try {
// Сохраняем сообщение пользователя в таблицу messages, включая данные файла
const userMessageResult = await db.query(
const userMessageResult = await db.getQuery()(
`INSERT INTO messages
(conversation_id, content, sender_type, role, channel, created_at, user_id,
attachment_filename, attachment_mimetype, attachment_size, attachment_data)
@@ -118,7 +118,7 @@ async function processGuestMessages(userId, guestId) {
if (aiResponseContent) {
// Сохраняем ответ от ИИ (у него нет вложений)
const aiMessageResult = await db.query(
const aiMessageResult = await db.getQuery()(
`INSERT INTO messages
(conversation_id, content, sender_type, role, channel, created_at, user_id)
VALUES
@@ -144,20 +144,20 @@ async function processGuestMessages(userId, guestId) {
// Удаляем только успешно обработанные гостевые сообщения
if (savedMessageIds.length > 0) {
await db.query('DELETE FROM guest_messages WHERE id = ANY($1::int[])', [savedMessageIds]);
await db.getQuery()('DELETE FROM guest_messages WHERE id = ANY($1::int[])', [savedMessageIds]);
logger.info(
`Deleted ${savedMessageIds.length} processed guest messages for guest ID ${guestId}`
);
// Помечаем гостевой ID как обработанный
await db.query('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [
await db.getQuery()('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [
guestId,
]);
logger.info(`Marked guest mapping as processed for guest ID ${guestId}`);
} else {
logger.warn(`No guest messages were successfully processed, skipping deletion for guest ID ${guestId}`);
// Если не было успешных, все равно пометим как обработанные, чтобы не пытаться снова
await db.query('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [guestId]);
await db.getQuery()('UPDATE guest_user_mapping SET processed = true WHERE guest_id = $1', [guestId]);
logger.info(`Marked guest mapping as processed (no successful messages) for guest ID ${guestId}`);
}
@@ -221,7 +221,7 @@ router.post('/guest-message', upload.array('attachments'), async (req, res) => {
});
// Сохраняем сообщение пользователя с текстом или файлом
const result = await db.query(
const result = await db.getQuery()(
`INSERT INTO guest_messages
(guest_id, content, language, is_ai,
attachment_filename, attachment_mimetype, attachment_size, attachment_data)
@@ -293,7 +293,7 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
try {
// Найти или создать диалог
if (conversationId) {
const convResult = await db.query(
const convResult = await db.getQuery()(
'SELECT * FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
@@ -308,7 +308,7 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
? (message.length > 50 ? `${message.substring(0, 50)}...` : message)
: (file ? `Файл: ${file.originalname}` : 'Новый диалог');
const newConvResult = await db.query(
const newConvResult = await db.getQuery()(
'INSERT INTO conversations (user_id, title) VALUES ($1, $2) RETURNING *',
[userId, title]
);
@@ -325,7 +325,7 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
const attachmentData = file ? file.buffer : null;
// Сохраняем сообщение пользователя
const userMessageResult = await db.query(
const userMessageResult = await db.getQuery()(
`INSERT INTO messages
(conversation_id, user_id, content, sender_type, role, channel,
attachment_filename, attachment_mimetype, attachment_size, attachment_data)
@@ -354,7 +354,7 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
logger.info('AI response received' + (aiResponseContent ? '' : ' (empty)'), { conversationId });
if (aiResponseContent) {
const aiMessageResult = await db.query(
const aiMessageResult = await db.getQuery()(
`INSERT INTO messages
(conversation_id, user_id, content, sender_type, role, channel)
VALUES ($1, $2, $3, 'assistant', 'assistant', 'web')
@@ -443,7 +443,7 @@ router.get('/history', requireAuth, async (req, res) => {
countQuery += ' AND conversation_id = $2';
countParams.push(conversationId);
}
const countResult = await db.query(countQuery, countParams);
const countResult = await db.getQuery()(countQuery, countParams);
const totalCount = parseInt(countResult.rows[0].count, 10);
return res.json({ success: true, count: totalCount });
}
@@ -481,7 +481,7 @@ router.get('/history', requireAuth, async (req, res) => {
logger.debug('Executing history query:', { query, params });
const result = await db.query(query, params);
const result = await db.getQuery()(query, params);
// Обрабатываем результаты для фронтенда
const messages = result.rows.map(msg => {
@@ -522,7 +522,7 @@ router.get('/history', requireAuth, async (req, res) => {
totalCountQuery += ' AND conversation_id = $2';
totalCountParams.push(conversationId);
}
const totalCountResult = await db.query(totalCountQuery, totalCountParams);
const totalCountResult = await db.getQuery()(totalCountQuery, totalCountParams);
const totalMessages = parseInt(totalCountResult.rows[0].count, 10);
logger.info(`Returning message history for user ${userId}`, { count: messages.length, offset, limit, total: totalMessages });

View File

@@ -11,7 +11,7 @@ const fs = require('fs');
* @desc Создать новое DLE (Digital Legal Entity)
* @access Private (только для авторизованных пользователей с ролью admin)
*/
router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res) => {
router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res, next) => {
try {
const dleParams = req.body;
logger.info('Получен запрос на создание DLE:', dleParams);
@@ -44,11 +44,7 @@ router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res) => {
});
} catch (error) {
logger.error('Ошибка при создании DLE:', error);
res.status(500).json({
success: false,
message: error.message || 'Произошла ошибка при создании DLE',
error: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
next(error);
}
});
@@ -57,7 +53,7 @@ router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res) => {
* @desc Получить список всех DLE
* @access Private (только для авторизованных пользователей)
*/
router.get('/', auth.requireAuth, async (req, res) => {
router.get('/', auth.requireAuth, async (req, res, next) => {
try {
const dles = await dleService.getAllDLEs();
res.json({
@@ -66,11 +62,7 @@ router.get('/', auth.requireAuth, async (req, res) => {
});
} catch (error) {
logger.error('Ошибка при получении списка DLE:', error);
res.status(500).json({
success: false,
message: error.message || 'Произошла ошибка при получении списка DLE',
error: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
next(error);
}
});
@@ -99,7 +91,7 @@ router.get('/settings', auth.requireAuth, (req, res) => {
* @desc Удалить DLE по адресу токена
* @access Private (только для авторизованных пользователей с ролью admin)
*/
router.delete('/:tokenAddress', auth.requireAuth, auth.requireAdmin, async (req, res) => {
router.delete('/:tokenAddress', auth.requireAuth, auth.requireAdmin, async (req, res, next) => {
try {
const { tokenAddress } = req.params;
logger.info(`Получен запрос на удаление DLE с адресом токена: ${tokenAddress}`);
@@ -142,11 +134,7 @@ router.delete('/:tokenAddress', auth.requireAuth, auth.requireAdmin, async (req,
});
} catch (error) {
logger.error('Ошибка при удалении DLE:', error);
res.status(500).json({
success: false,
message: error.message || 'Произошла ошибка при удалении DLE',
error: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
next(error);
}
});
@@ -155,7 +143,7 @@ router.delete('/:tokenAddress', auth.requireAuth, auth.requireAdmin, async (req,
* @desc Удалить пустое DLE по имени файла
* @access Private (только для авторизованных пользователей с ролью admin)
*/
router.delete('/empty/:fileName', auth.requireAuth, auth.requireAdmin, async (req, res) => {
router.delete('/empty/:fileName', auth.requireAuth, auth.requireAdmin, async (req, res, next) => {
try {
const { fileName } = req.params;
logger.info(`Получен запрос на удаление пустого DLE с именем файла: ${fileName}`);
@@ -180,11 +168,7 @@ router.delete('/empty/:fileName', auth.requireAuth, auth.requireAdmin, async (re
});
} catch (error) {
logger.error('Ошибка при удалении пустого DLE:', error);
res.status(500).json({
success: false,
message: error.message || 'Произошла ошибка при удалении пустого DLE',
error: process.env.NODE_ENV === 'development' ? error.stack : undefined
});
next(error);
}
});

View File

@@ -6,19 +6,19 @@ const logger = require('../utils/logger');
const db = require('../db');
// Получение всех идентификаторов пользователя
router.get('/', requireAuth, async (req, res) => {
router.get('/', requireAuth, async (req, res, next) => {
try {
const userId = req.session.userId;
const identities = await authService.getUserIdentities(userId);
res.json({ success: true, identities });
} catch (error) {
logger.error('Error getting identities:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Связывание нового идентификатора
router.post('/link', requireAuth, async (req, res) => {
router.post('/link', requireAuth, async (req, res, next) => {
try {
const { type, value } = req.body;
const userId = req.session.userId;
@@ -28,7 +28,7 @@ router.post('/link', requireAuth, async (req, res) => {
const normalizedWallet = value.toLowerCase();
// Проверяем, существует ли уже такой кошелек
const existingCheck = await db.query(
const existingCheck = await db.getQuery()(
`SELECT user_id FROM user_identities
WHERE provider = 'wallet' AND provider_id = $1`,
[normalizedWallet]
@@ -73,12 +73,12 @@ router.post('/link', requireAuth, async (req, res) => {
});
}
res.status(500).json({ error: error.message || 'Internal server error' });
next(error);
}
});
// Получение балансов токенов
router.get('/token-balances', requireAuth, async (req, res) => {
router.get('/token-balances', requireAuth, async (req, res, next) => {
try {
const userId = req.session.userId;
if (!userId) {
@@ -103,12 +103,12 @@ router.get('/token-balances', requireAuth, async (req, res) => {
});
} catch (error) {
logger.error('Error getting token balances:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Удаление идентификатора пользователя
router.delete('/:provider/:providerId', requireAuth, async (req, res) => {
router.delete('/:provider/:providerId', requireAuth, async (req, res, next) => {
try {
const userId = req.session.userId;
const { provider, providerId } = req.params;
@@ -120,7 +120,135 @@ router.delete('/:provider/:providerId', requireAuth, async (req, res) => {
}
} catch (error) {
logger.error('Error deleting identity:', error);
res.status(500).json({ error: 'Internal server error' });
next(error);
}
});
// Получение email-настроек
router.get('/email-settings', requireAuth, async (req, res, next) => {
try {
const { rows } = await db.getQuery()('SELECT * FROM email_settings ORDER BY id LIMIT 1');
if (!rows.length) return res.status(404).json({ success: false, error: 'Not found' });
const settings = rows[0];
delete settings.smtp_password; // не возвращаем пароль
res.json({ success: true, settings });
} catch (error) {
logger.error('Error getting email settings:', error, error && error.stack);
next(error);
}
});
// Обновление email-настроек
router.put('/email-settings', requireAuth, async (req, res, next) => {
try {
const { smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email } = req.body;
if (!smtp_host || !smtp_port || !smtp_user || !from_email) {
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
const { rows } = await db.getQuery()('SELECT id FROM email_settings ORDER BY id LIMIT 1');
if (rows.length) {
// Обновляем существующую запись
await db.getQuery()(
`UPDATE email_settings SET smtp_host=$1, smtp_port=$2, smtp_user=$3, smtp_password=COALESCE($4, smtp_password), imap_host=$5, imap_port=$6, from_email=$7, updated_at=NOW() WHERE id=$8`,
[smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email, rows[0].id]
);
} else {
// Вставляем новую
await db.getQuery()(
`INSERT INTO email_settings (smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email) VALUES ($1,$2,$3,$4,$5,$6,$7)`,
[smtp_host, smtp_port, smtp_user, smtp_password, imap_host, imap_port, from_email]
);
}
res.json({ success: true });
} catch (error) {
logger.error('Error updating email settings:', error);
next(error);
}
});
// Получение telegram-настроек
router.get('/telegram-settings', requireAuth, async (req, res, next) => {
try {
const { rows } = await db.getQuery()('SELECT * FROM telegram_settings ORDER BY id LIMIT 1');
if (!rows.length) return res.status(404).json({ success: false, error: 'Not found' });
const settings = rows[0];
delete settings.bot_token; // не возвращаем токен
res.json({ success: true, settings });
} catch (error) {
logger.error('Error getting telegram settings:', error, error && error.stack);
next(error);
}
});
// Обновление telegram-настроек
router.put('/telegram-settings', requireAuth, async (req, res, next) => {
try {
const { bot_token, bot_username } = req.body;
if (!bot_token || !bot_username) {
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
const { rows } = await db.getQuery()('SELECT id FROM telegram_settings ORDER BY id LIMIT 1');
if (rows.length) {
// Обновляем существующую запись
await db.getQuery()(
`UPDATE telegram_settings SET bot_token=$1, bot_username=$2, updated_at=NOW() WHERE id=$3`,
[bot_token, bot_username, rows[0].id]
);
} else {
// Вставляем новую
await db.getQuery()(
`INSERT INTO telegram_settings (bot_token, bot_username) VALUES ($1,$2)` ,
[bot_token, bot_username]
);
}
res.json({ success: true });
} catch (error) {
logger.error('Error updating telegram settings:', error);
next(error);
}
});
// Получение db-настроек
router.get('/db-settings', requireAuth, async (req, res, next) => {
try {
const { rows } = await db.getQuery()('SELECT * FROM db_settings ORDER BY id LIMIT 1');
if (!rows.length) return res.status(404).json({ success: false, error: 'Not found' });
const settings = rows[0];
delete settings.db_password; // не возвращаем пароль
res.json({ success: true, settings });
} catch (error) {
logger.error('Error getting db settings:', error, error && error.stack);
next(error);
}
});
// Обновление db-настроек
router.put('/db-settings', requireAuth, async (req, res, next) => {
try {
const { db_host, db_port, db_name, db_user, db_password } = req.body;
if (!db_host || !db_port || !db_name || !db_user) {
return res.status(400).json({ success: false, error: 'Missing required fields' });
}
const { rows } = await db.getQuery()('SELECT id FROM db_settings ORDER BY id LIMIT 1');
if (rows.length) {
// Обновляем существующую запись
await db.getQuery()(
`UPDATE db_settings SET db_host=$1, db_port=$2, db_name=$3, db_user=$4, db_password=COALESCE($5, db_password), updated_at=NOW() WHERE id=$6`,
[db_host, db_port, db_name, db_user, db_password, rows[0].id]
);
} else {
// Вставляем новую
await db.getQuery()(
`INSERT INTO db_settings (db_host, db_port, db_name, db_user, db_password) VALUES ($1,$2,$3,$4,$5)` ,
[db_host, db_port, db_name, db_user, db_password]
);
}
// Пересоздаём пул соединений с новыми настройками
await db.reinitPoolFromDbSettings();
res.json({ success: true });
} catch (error) {
logger.error('Error updating db settings:', error);
next(error);
}
});

View File

@@ -1,6 +1,6 @@
const express = require('express');
const router = express.Router();
const { pool } = require('../db'); // Убедитесь, что путь к вашему db-коннектору правильный
const db = require('../db');
const logger = require('../utils/logger'); // Если используете логгер
/**
@@ -98,7 +98,7 @@ router.get('/codes', async (req, res) => {
if (parent_code) {
try {
const parentResult = await pool.query('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]);
const parentResult = await db.getQuery()('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]);
if (parentResult.rows.length > 0) {
const parentLevel = parentResult.rows[0].code_level;
if (parentLevel >= 1 && parentLevel < 6) {
@@ -146,7 +146,7 @@ router.get('/codes', async (req, res) => {
}
if (parent_code) {
// Предполагаем, что parent_code уже добавлен в countQueryParams
const parentLevelResult = await pool.query('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]); // Нужно будет передать parent_code в countQueryParams
const parentLevelResult = await db.getQuery()('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]); // Нужно будет передать parent_code в countQueryParams
if (parentLevelResult.rows.length > 0) {
const parentLevel = parentLevelResult.rows[0].code_level;
if (parentLevel >=1 && parentLevel < 6) {
@@ -174,7 +174,7 @@ router.get('/codes', async (req, res) => {
const queryWhereConditions = [];
if (level) queryWhereConditions.push(`c.code_level = $${currentQueryParamIndex++}`);
if (parent_code) {
const parentLevelResult = await pool.query('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]); // Это дублирование, лучше получить parentLevel один раз
const parentLevelResult = await db.getQuery()('SELECT code_level FROM isic_rev4_codes WHERE code = $1', [parent_code]); // Это дублирование, лучше получить parentLevel один раз
if (parentLevelResult.rows.length > 0) {
const parentLevel = parentLevelResult.rows[0].code_level;
if (parentLevel >=1 && parentLevel < 6) {
@@ -193,12 +193,12 @@ router.get('/codes', async (req, res) => {
try {
logger.debug('Executing count query:', finalCountQuery, 'Params:', countQueryParams);
const totalItemsResult = await pool.query(finalCountQuery, countQueryParams);
const totalItemsResult = await db.getQuery()(finalCountQuery, countQueryParams);
const totalItems = parseInt(totalItemsResult.rows[0].total, 10);
// Параметры для основного запроса - это все, что в queryParams (включая limit и offset)
logger.debug('Executing data query:', finalQuery, 'Params:', queryParams);
const result = await pool.query(finalQuery, queryParams);
const result = await db.getQuery()(finalQuery, queryParams);
res.json({
totalItems,
@@ -253,13 +253,13 @@ router.get('/tree', async (req, res) => {
try {
let items;
if (!root_code) { // Если нет root_code, возвращаем секции (уровень 1)
const result = await pool.query(
const result = await db.getQuery()(
"SELECT code, description, code_level FROM isic_rev4_codes WHERE code_level = 1 ORDER BY sort_order, code"
);
items = result.rows.map(row => ({ ...row, children: [] })); // Добавляем пустой массив children
} else {
// Получаем сам root_code
const rootResult = await pool.query(
const rootResult = await db.getQuery()(
"SELECT code, description, code_level FROM isic_rev4_codes WHERE code = $1",
[root_code]
);
@@ -281,7 +281,7 @@ router.get('/tree', async (req, res) => {
if (childrenQuery) {
const childrenResult = await pool.query(childrenQuery, childrenParams);
const childrenResult = await db.getQuery()(childrenQuery, childrenParams);
rootNode.children = childrenResult.rows.map(row => ({ ...row, children: [] }));
}
items = [rootNode];

View File

@@ -5,23 +5,25 @@ const logger = require('../utils/logger');
const { ethers } = require('ethers');
const rpcProviderService = require('../services/rpcProviderService');
const authTokenService = require('../services/authTokenService');
const aiProviderSettingsService = require('../services/aiProviderSettingsService');
const aiAssistant = require('../services/ai-assistant');
// Логируем версию ethers для отладки
logger.info(`Ethers version: ${ethers.version || 'unknown'}`);
// Получение RPC настроек
router.get('/rpc', requireAdmin, async (req, res) => {
router.get('/rpc', requireAdmin, async (req, res, next) => {
try {
const rpcConfigs = await rpcProviderService.getAllRpcProviders();
res.json({ success: true, data: rpcConfigs });
} catch (error) {
logger.error('Ошибка при получении RPC настроек:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при получении настроек RPC' });
next(error);
}
});
// Добавление/обновление одного или нескольких RPC
router.post('/rpc', requireAdmin, async (req, res) => {
router.post('/rpc', requireAdmin, async (req, res, next) => {
try {
// Если пришёл массив rpcConfigs — bulk-режим
if (Array.isArray(req.body.rpcConfigs)) {
@@ -41,35 +43,35 @@ router.post('/rpc', requireAdmin, async (req, res) => {
res.json({ success: true, message: 'RPC провайдер сохранён' });
} catch (error) {
logger.error('Ошибка при сохранении RPC:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении RPC' });
next(error);
}
});
// Удаление одного RPC
router.delete('/rpc/:networkId', requireAdmin, async (req, res) => {
router.delete('/rpc/:networkId', requireAdmin, async (req, res, next) => {
try {
const { networkId } = req.params;
await rpcProviderService.deleteRpcProvider(networkId);
res.json({ success: true, message: 'RPC провайдер удалён' });
} catch (error) {
logger.error('Ошибка при удалении RPC:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при удалении RPC' });
next(error);
}
});
// Получение токенов для аутентификации
router.get('/auth-tokens', requireAdmin, async (req, res) => {
router.get('/auth-tokens', requireAdmin, async (req, res, next) => {
try {
const authTokens = await authTokenService.getAllAuthTokens();
res.json({ success: true, data: authTokens });
} catch (error) {
logger.error('Ошибка при получении токенов аутентификации:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при получении токенов аутентификации' });
next(error);
}
});
// Сохранение токенов для аутентификации
router.post('/auth-tokens', requireAdmin, async (req, res) => {
router.post('/auth-tokens', requireAdmin, async (req, res, next) => {
try {
const { authTokens } = req.body;
if (!Array.isArray(authTokens)) {
@@ -79,12 +81,12 @@ router.post('/auth-tokens', requireAdmin, async (req, res) => {
res.json({ success: true, message: 'Токены аутентификации успешно сохранены' });
} catch (error) {
logger.error('Ошибка при сохранении токенов аутентификации:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении токенов аутентификации' });
next(error);
}
});
// Добавление/обновление одного токена
router.post('/auth-token', requireAdmin, async (req, res) => {
router.post('/auth-token', requireAdmin, async (req, res, next) => {
try {
const { name, address, network, minBalance } = req.body;
if (!name || !address || !network) {
@@ -94,24 +96,24 @@ router.post('/auth-token', requireAdmin, async (req, res) => {
res.json({ success: true, message: 'Токен аутентификации сохранён' });
} catch (error) {
logger.error('Ошибка при сохранении токена аутентификации:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении токена' });
next(error);
}
});
// Удаление одного токена
router.delete('/auth-token/:address/:network', requireAdmin, async (req, res) => {
router.delete('/auth-token/:address/:network', requireAdmin, async (req, res, next) => {
try {
const { address, network } = req.params;
await authTokenService.deleteAuthToken(address, network);
res.json({ success: true, message: 'Токен аутентификации удалён' });
} catch (error) {
logger.error('Ошибка при удалении токена аутентификации:', error);
res.status(500).json({ success: false, error: 'Ошибка сервера при удалении токена' });
next(error);
}
});
// Тестирование RPC соединения
router.post('/rpc-test', requireAdmin, async (req, res) => {
router.post('/rpc-test', requireAdmin, async (req, res, next) => {
try {
const { rpcUrl, networkId } = req.body;
@@ -164,4 +166,76 @@ router.post('/rpc-test', requireAdmin, async (req, res) => {
}
});
// Получить настройки AI-провайдера
router.get('/ai-settings/:provider', requireAdmin, async (req, res, next) => {
try {
const { provider } = req.params;
const settings = await aiProviderSettingsService.getProviderSettings(provider);
res.json({ success: true, settings });
} catch (error) {
logger.error('Ошибка при получении AI-настроек:', error);
next(error);
}
});
// Сохранить/обновить настройки AI-провайдера
router.put('/ai-settings/:provider', requireAdmin, async (req, res, next) => {
try {
const { provider } = req.params;
const { api_key, base_url, selected_model } = req.body;
const updated = await aiProviderSettingsService.upsertProviderSettings({ provider, api_key, base_url, selected_model });
res.json({ success: true, settings: updated });
} catch (error) {
logger.error('Ошибка при сохранении AI-настроек:', error);
next(error);
}
});
// Удалить настройки AI-провайдера
router.delete('/ai-settings/:provider', requireAdmin, async (req, res, next) => {
try {
const { provider } = req.params;
await aiProviderSettingsService.deleteProviderSettings(provider);
res.json({ success: true });
} catch (error) {
logger.error('Ошибка при удалении AI-настроек:', error);
next(error);
}
});
// Получить список моделей для провайдера
router.get('/ai-settings/:provider/models', requireAdmin, async (req, res, next) => {
try {
const { provider } = req.params;
const settings = await aiProviderSettingsService.getProviderSettings(provider);
let models = [];
if (provider === 'ollama') {
models = await aiAssistant.getAvailableModels();
} else {
models = await aiProviderSettingsService.getProviderModels(provider, settings || {});
}
res.json({ success: true, models });
} catch (error) {
logger.error('Ошибка при получении моделей AI:', error);
res.status(500).json({ success: false, error: error.message });
}
});
// Проверить валидность ключа (verify)
router.post('/ai-settings/:provider/verify', requireAdmin, async (req, res, next) => {
try {
const { provider } = req.params;
const { api_key, base_url } = req.body;
const result = await aiProviderSettingsService.verifyProviderKey(provider, { api_key, base_url });
if (result.success) {
res.json({ success: true });
} else {
res.status(400).json({ success: false, error: result.error });
}
} catch (error) {
logger.error('Ошибка при проверке AI-ключа:', error);
res.status(500).json({ success: false, error: error.message });
}
});
module.exports = router;

View File

@@ -4,7 +4,7 @@ const logger = require('../utils/logger');
const authService = require('../services/auth-service');
// Получение балансов токенов пользователя по токенам из базы
router.get('/balances', async (req, res) => {
router.get('/balances', async (req, res, next) => {
try {
const address = req.query.address;
if (!address) {
@@ -15,7 +15,7 @@ router.get('/balances', async (req, res) => {
res.json({ success: true, data: balances });
} catch (error) {
logger.error('Error fetching token balances:', error);
res.status(500).json({ success: false, error: 'Failed to fetch token balances' });
next(error);
}
});

View File

@@ -20,53 +20,42 @@ router.get('/:address', (req, res) => {
});
// Маршрут для обновления языка пользователя
router.post('/update-language', requireAuth, async (req, res) => {
router.post('/update-language', requireAuth, async (req, res, next) => {
try {
const { language } = req.body;
const userId = req.session.userId;
// Проверка валидности языка
const validLanguages = ['ru', 'en'];
if (!validLanguages.includes(language)) {
return res.status(400).json({ error: 'Неподдерживаемый язык' });
}
// Обновление языка в базе данных
await db.query('UPDATE users SET preferred_language = $1 WHERE id = $2', [language, userId]);
await db.getQuery()('UPDATE users SET preferred_language = $1 WHERE id = $2', [language, userId]);
res.json({ success: true });
} catch (error) {
logger.error('Error updating language:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
next(error);
}
});
// Маршрут для обновления имени и фамилии пользователя
router.post('/update-profile', requireAuth, async (req, res) => {
router.post('/update-profile', requireAuth, async (req, res, next) => {
try {
const { firstName, lastName } = req.body;
const userId = req.session.userId;
// Проверка валидности данных
if (firstName && firstName.length > 255) {
return res.status(400).json({ error: 'Имя слишком длинное (максимум 255 символов)' });
}
if (lastName && lastName.length > 255) {
return res.status(400).json({ error: 'Фамилия слишком длинная (максимум 255 символов)' });
}
// Обновление имени и фамилии в базе данных
await db.query('UPDATE users SET first_name = $1, last_name = $2 WHERE id = $3', [
await db.getQuery()('UPDATE users SET first_name = $1, last_name = $2 WHERE id = $3', [
firstName || null,
lastName || null,
userId,
]);
res.json({ success: true });
} catch (error) {
logger.error('Error updating user profile:', error);
res.status(500).json({ error: 'Внутренняя ошибка сервера' });
next(error);
}
});