feat: новая функция
This commit is contained in:
@@ -38,7 +38,8 @@ router.post('/task', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { message, language, history, systemPrompt, rules, type = 'chat' } = req.body;
|
||||
const userId = req.session.userId;
|
||||
const userRole = req.session.isAdmin ? 'admin' : 'user';
|
||||
const userAccessLevel = req.session.userAccessLevel || { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
const userRole = userAccessLevel.hasAccess ? 'admin' : 'user';
|
||||
|
||||
if (!message) {
|
||||
return res.status(400).json({
|
||||
@@ -108,7 +109,7 @@ router.post('/control', requireAuth, async (req, res) => {
|
||||
try {
|
||||
const { action } = req.body;
|
||||
|
||||
if (!req.session.isAdmin) {
|
||||
if (!req.session.userAccessLevel?.hasAccess) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: 'Admin access required'
|
||||
|
||||
@@ -207,7 +207,7 @@ router.post('/verify', async (req, res) => {
|
||||
logger.info(`[verify] Admin status for ${normalizedAddress}: ${adminStatus}`);
|
||||
|
||||
let userId;
|
||||
let isAdmin = adminStatus;
|
||||
let userAccessLevel = adminStatus ? { level: 'editor', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
|
||||
// Проверяем, авторизован ли пользователь уже
|
||||
if (req.session.authenticated && req.session.userId) {
|
||||
@@ -226,10 +226,10 @@ router.post('/verify', async (req, res) => {
|
||||
);
|
||||
} else {
|
||||
// Находим или создаем пользователя с уже известной ролью
|
||||
const result = await authService.findOrCreateUser(address, adminStatus);
|
||||
const result = await authService.findOrCreateUser(address, userAccessLevel);
|
||||
userId = result.userId;
|
||||
isAdmin = result.isAdmin;
|
||||
logger.info(`[verify] Found or created user ${userId} for wallet ${normalizedAddress} with admin status: ${isAdmin}`);
|
||||
userAccessLevel = result.userAccessLevel;
|
||||
logger.info(`[verify] Found or created user ${userId} for wallet ${normalizedAddress} with access level: ${userAccessLevel.hasAccess}`);
|
||||
}
|
||||
|
||||
// Сохраняем идентификаторы гостевой сессии
|
||||
@@ -245,7 +245,7 @@ router.post('/verify', async (req, res) => {
|
||||
req.session.userId = userId;
|
||||
req.session.authenticated = true;
|
||||
req.session.authType = 'wallet';
|
||||
req.session.isAdmin = adminStatus || isAdmin;
|
||||
req.session.userAccessLevel = userAccessLevel;
|
||||
req.session.address = normalizedAddress; // Всегда сохраняем нормализованный адрес
|
||||
|
||||
// Удаляем временный ID
|
||||
@@ -258,11 +258,12 @@ router.post('/verify', async (req, res) => {
|
||||
await sessionService.linkGuestMessages(req.session, userId);
|
||||
|
||||
// Возвращаем успешный ответ
|
||||
userAccessLevel = await authService.getUserAccessLevel(normalizedAddress);
|
||||
return res.json({
|
||||
success: true,
|
||||
userId,
|
||||
address: normalizedAddress, // Возвращаем нормализованный адрес
|
||||
isAdmin: adminStatus || isAdmin,
|
||||
userAccessLevel: userAccessLevel,
|
||||
authenticated: true,
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -347,7 +348,7 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
req.session.telegramId = telegramId;
|
||||
req.session.authType = 'telegram';
|
||||
req.session.authenticated = true;
|
||||
req.session.isAdmin = finalIsAdmin; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||
req.session.userAccessLevel = finalIsAdmin ? { level: 'editor', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false }; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||
|
||||
// ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ (ЕСЛИ НАЙДЕН) <---
|
||||
if (linkedWalletAddress) {
|
||||
@@ -368,10 +369,16 @@ router.post('/telegram/verify', async (req, res) => {
|
||||
await sessionService.linkGuestMessages(req.session, verificationResult.userId);
|
||||
}
|
||||
|
||||
// Получаем уровень доступа для пользователя
|
||||
let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
if (linkedWalletAddress) {
|
||||
userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
userId: verificationResult.userId,
|
||||
isAdmin: finalIsAdmin, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНУЮ РОЛЬ
|
||||
userAccessLevel: userAccessLevel, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНЫЙ УРОВЕНЬ ДОСТУПА
|
||||
telegramId,
|
||||
isNewUser: verificationResult.isNewUser,
|
||||
address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
|
||||
@@ -511,7 +518,7 @@ router.post('/email/verify-code', async (req, res) => {
|
||||
req.session.authenticated = true;
|
||||
req.session.authType = 'email';
|
||||
req.session.email = authResult.email;
|
||||
req.session.isAdmin = finalIsAdmin; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||
req.session.userAccessLevel = finalIsAdmin ? { level: 'editor', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false }; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||
// ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ <---
|
||||
if (linkedWalletAddress) {
|
||||
req.session.address = linkedWalletAddress;
|
||||
@@ -533,11 +540,17 @@ router.post('/email/verify-code', async (req, res) => {
|
||||
await sessionService.linkGuestMessages(req.session, authResult.userId);
|
||||
|
||||
// 4. Отправляем ответ
|
||||
// Получаем уровень доступа для пользователя
|
||||
let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
if (linkedWalletAddress) {
|
||||
userAccessLevel = await authService.getUserAccessLevel(linkedWalletAddress);
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
userId: authResult.userId,
|
||||
email: authResult.email,
|
||||
isAdmin: finalIsAdmin, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНУЮ РОЛЬ
|
||||
userAccessLevel: userAccessLevel, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНЫЙ УРОВЕНЬ ДОСТУПА
|
||||
authenticated: true,
|
||||
isNewAuth: authResult.isNewUser,
|
||||
address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
|
||||
@@ -630,7 +643,7 @@ router.get('/check', async (req, res) => {
|
||||
const authType = req.session.authType || null;
|
||||
|
||||
let identities = [];
|
||||
let isAdmin = false;
|
||||
let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
|
||||
if (authenticated && req.session.userId) {
|
||||
// Если пользователь аутентифицирован, получаем его идентификаторы из БД
|
||||
@@ -639,8 +652,8 @@ router.get('/check', async (req, res) => {
|
||||
|
||||
// Для пользователей с кошельком проверяем токены в реальном времени
|
||||
if (authType === 'wallet' && req.session.address) {
|
||||
isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
logger.info(`[auth/check] Admin status for wallet ${req.session.address}: ${isAdmin}`);
|
||||
userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
logger.info(`[auth/check] Access level for wallet ${req.session.address}:`, userAccessLevel);
|
||||
} else {
|
||||
// Для других типов аутентификации используем роль из БД
|
||||
const roleResult = await db.getQuery()('SELECT role FROM users WHERE id = $1', [
|
||||
@@ -648,11 +661,17 @@ router.get('/check', async (req, res) => {
|
||||
]);
|
||||
|
||||
if (roleResult.rows.length > 0) {
|
||||
isAdmin = roleResult.rows[0].role === 'admin';
|
||||
const role = roleResult.rows[0].role;
|
||||
// Преобразуем старую роль в новый формат
|
||||
if (role === 'admin') {
|
||||
userAccessLevel = { level: 'editor', tokenCount: 1, hasAccess: true };
|
||||
} else {
|
||||
userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.session.isAdmin = isAdmin;
|
||||
req.session.userAccessLevel = userAccessLevel;
|
||||
} catch (error) {
|
||||
logger.error(`[session/check] Error fetching identities: ${error.message}`);
|
||||
}
|
||||
@@ -674,7 +693,7 @@ router.get('/check', async (req, res) => {
|
||||
guestId: req.session.guestId || null,
|
||||
authType,
|
||||
identitiesCount: identities.length,
|
||||
isAdmin: isAdmin || false,
|
||||
userAccessLevel: userAccessLevel,
|
||||
};
|
||||
|
||||
// Добавляем специфические поля в зависимости от типа аутентификации
|
||||
@@ -711,7 +730,7 @@ router.post('/logout', async (req, res) => {
|
||||
req.session.address = null;
|
||||
req.session.telegramId = null;
|
||||
req.session.email = null;
|
||||
req.session.isAdmin = false;
|
||||
req.session.userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
req.session.guestId = null;
|
||||
req.session.previousGuestId = null;
|
||||
req.session.processedGuestIds = [];
|
||||
@@ -743,15 +762,15 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
const address = req.session.address;
|
||||
|
||||
if (address) {
|
||||
const isAdmin = await authService.checkAdminTokens(address);
|
||||
const userAccessLevel = await authService.getUserAccessLevel(address);
|
||||
|
||||
// Обновляем сессию
|
||||
req.session.isAdmin = isAdmin;
|
||||
req.session.userAccessLevel = userAccessLevel;
|
||||
await sessionService.saveSession(req.session);
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
isAdmin,
|
||||
userAccessLevel,
|
||||
userId,
|
||||
address,
|
||||
});
|
||||
@@ -759,7 +778,7 @@ router.get('/check-access', requireAuth, async (req, res) => {
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
isAdmin: false,
|
||||
userAccessLevel: { level: 'user', tokenCount: 0, hasAccess: false },
|
||||
userId,
|
||||
address: null,
|
||||
});
|
||||
@@ -794,7 +813,7 @@ router.post('/refresh-session', async (req, res) => {
|
||||
req.session.authenticated = true;
|
||||
req.session.userId = user.id;
|
||||
req.session.address = address.toLowerCase();
|
||||
req.session.isAdmin = user.role === 'admin';
|
||||
req.session.userAccessLevel = user.role === 'admin' ? { level: 'editor', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
req.session.authType = 'wallet';
|
||||
|
||||
// Сохраняем обновленную сессию
|
||||
@@ -847,10 +866,10 @@ router.post('/wallet', async (req, res) => {
|
||||
const { userId } = await authService.findOrCreateUser(address);
|
||||
|
||||
// Проверяем наличие админских токенов
|
||||
const isAdmin = await authService.checkAdminTokens(address);
|
||||
const userAccessLevel = await authService.getUserAccessLevel(address);
|
||||
|
||||
// Обновляем роль пользователя в базе данных, если нужно
|
||||
if (isAdmin) {
|
||||
if (userAccessLevel.hasAccess) {
|
||||
await db.getQuery()('UPDATE users SET role = $1 WHERE id = $2', ['admin', userId]);
|
||||
}
|
||||
|
||||
@@ -870,7 +889,7 @@ router.post('/wallet', async (req, res) => {
|
||||
req.session.address = address.toLowerCase();
|
||||
req.session.authType = 'wallet';
|
||||
req.session.authenticated = true;
|
||||
req.session.isAdmin = isAdmin;
|
||||
req.session.userAccessLevel = userAccessLevel;
|
||||
|
||||
// Сохраняем сессию
|
||||
await sessionService.saveSession(req.session);
|
||||
@@ -883,7 +902,7 @@ router.post('/wallet', async (req, res) => {
|
||||
success: true,
|
||||
userId,
|
||||
address,
|
||||
isAdmin,
|
||||
userAccessLevel,
|
||||
authenticated: true,
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -1039,7 +1058,8 @@ router.post('/wallet-with-link', authLimiter, async (req, res) => {
|
||||
req.session.address = address.toLowerCase();
|
||||
req.session.authenticated = true;
|
||||
req.session.authType = 'wallet';
|
||||
req.session.isAdmin = (role === 'admin' || role === 'editor' || role === 'readonly');
|
||||
const hasAccess = (role === 'admin' || role === 'editor' || role === 'readonly');
|
||||
req.session.userAccessLevel = hasAccess ? { level: role === 'editor' ? 'editor' : 'readonly', tokenCount: 0, hasAccess: true } : { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
|
||||
await sessionService.saveSession(req.session, 'wallet-with-link');
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ const db = require('../db');
|
||||
const encryptedDb = require('../services/encryptedDatabaseService');
|
||||
const logger = require('../utils/logger');
|
||||
const { requireAuth, requireAdmin } = require('../middleware/auth');
|
||||
const { requirePermission } = require('../middleware/permissions');
|
||||
const { PERMISSIONS } = require('../shared/permissions');
|
||||
const aiAssistantSettingsService = require('../services/aiAssistantSettingsService');
|
||||
const aiAssistantRulesService = require('../services/aiAssistantRulesService');
|
||||
const botManager = require('../services/botManager');
|
||||
@@ -208,10 +210,9 @@ router.post('/message', requireAuth, upload.array('attachments'), async (req, re
|
||||
const adminLogicService = require('../services/adminLogicService');
|
||||
const sessionUserId = req.session.userId;
|
||||
const targetUserId = userId;
|
||||
const isAdmin = req.session.isAdmin || false;
|
||||
|
||||
const userAccessLevel = req.session.userAccessLevel || { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
const canWrite = adminLogicService.canWriteToConversation({
|
||||
isAdmin: isAdmin,
|
||||
userAccessLevel: userAccessLevel,
|
||||
userId: sessionUserId,
|
||||
conversationUserId: targetUserId
|
||||
});
|
||||
@@ -431,7 +432,8 @@ router.post('/process-guest', requireAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// POST /api/chat/ai-draft — генерация черновика ответа ИИ
|
||||
router.post('/ai-draft', requireAuth, async (req, res) => {
|
||||
// Генерация AI-черновика ответа (только для админов-редакторов)
|
||||
router.post('/ai-draft', requireAuth, requirePermission(PERMISSIONS.GENERATE_AI_REPLIES), async (req, res) => {
|
||||
const userId = req.session.userId;
|
||||
const { conversationId, messages, language } = req.body;
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@ const UnifiedDeploymentService = require('../services/unifiedDeploymentService')
|
||||
const unifiedDeploymentService = new UnifiedDeploymentService();
|
||||
const logger = require('../utils/logger');
|
||||
const auth = require('../middleware/auth');
|
||||
const authService = require('../services/auth-service');
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: используем shared/permissions.js
|
||||
const { hasPermission, ROLES, PERMISSIONS } = require('/app/shared/permissions');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const ethers = require('ethers'); // Added ethers for private key validation
|
||||
@@ -61,6 +64,26 @@ router.post('/', auth.requireAuth, auth.requireAdmin, async (req, res, next) =>
|
||||
|
||||
// Если параметр initialPartners не был передан явно, используем адрес авторизованного пользователя
|
||||
if (!dleParams.initialPartners || dleParams.initialPartners.length === 0) {
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: проверяем права через новую систему
|
||||
let userRole = ROLES.GUEST;
|
||||
if (req.user?.userAccessLevel) {
|
||||
if (req.user.userAccessLevel.level === 'readonly') {
|
||||
userRole = ROLES.READONLY;
|
||||
} else if (req.user.userAccessLevel.level === 'editor') {
|
||||
userRole = ROLES.EDITOR;
|
||||
}
|
||||
} else if (req.user?.id) {
|
||||
userRole = ROLES.USER;
|
||||
}
|
||||
|
||||
// Проверяем права на управление настройками
|
||||
if (!hasPermission(userRole, PERMISSIONS.MANAGE_SETTINGS)) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: 'Insufficient permissions for DLE deployment'
|
||||
});
|
||||
}
|
||||
|
||||
// Проверяем, есть ли в сессии адрес кошелька пользователя
|
||||
if (!req.user || !req.user.walletAddress) {
|
||||
return res.status(400).json({
|
||||
@@ -245,15 +268,13 @@ router.get('/check-admin-tokens', async (req, res, next) => {
|
||||
}
|
||||
|
||||
// Проверяем баланс токенов
|
||||
const { checkAdminRole } = require('../services/admin-role');
|
||||
const isAdmin = await checkAdminRole(address);
|
||||
|
||||
const userAccessLevel = await authService.getUserAccessLevel(address);
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
isAdmin: isAdmin,
|
||||
userAccessLevel: userAccessLevel,
|
||||
address: address,
|
||||
message: isAdmin ? 'Админские токены найдены' : 'Админские токены не найдены'
|
||||
message: userAccessLevel.hasAccess ? 'Админские токены найдены' : 'Админские токены не найдены'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -69,7 +69,8 @@ router.post('/link', requireAuth, async (req, res, next) => {
|
||||
// Обновляем сессию
|
||||
if (type === 'wallet') {
|
||||
req.session.address = value;
|
||||
req.session.isAdmin = await authService.checkTokensAndUpdateRole(value);
|
||||
const userAccessLevel = await authService.getUserAccessLevel(value);
|
||||
req.session.userAccessLevel = userAccessLevel;
|
||||
} else if (type === 'telegram') {
|
||||
req.session.telegramId = value;
|
||||
} else if (type === 'email') {
|
||||
@@ -79,7 +80,7 @@ router.post('/link', requireAuth, async (req, res, next) => {
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'Identity linked successfully',
|
||||
isAdmin: req.session.isAdmin,
|
||||
userAccessLevel: req.session.userAccessLevel || { level: 'user', tokenCount: 0, hasAccess: false },
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Error linking identity:', error);
|
||||
|
||||
@@ -16,9 +16,14 @@ const db = require('../db');
|
||||
const { broadcastMessagesUpdate } = require('../wsHub');
|
||||
const botManager = require('../services/botManager');
|
||||
const { isUserBlocked } = require('../utils/userUtils');
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { requirePermission } = require('../middleware/permissions');
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: используем shared/permissions.js
|
||||
const { hasPermission, ROLES, PERMISSIONS } = require('/app/shared/permissions');
|
||||
|
||||
// GET /api/messages?userId=123
|
||||
router.get('/', async (req, res) => {
|
||||
// Просмотр сообщений конкретного пользователя (для админов в CRM)
|
||||
router.get('/', requireAuth, requirePermission(PERMISSIONS.VIEW_CONTACTS), async (req, res) => {
|
||||
const userId = req.query.userId;
|
||||
const conversationId = req.query.conversationId;
|
||||
|
||||
@@ -263,12 +268,16 @@ router.post('/mark-read', async (req, res) => {
|
||||
try {
|
||||
// console.log('[DEBUG] /mark-read req.user:', req.user);
|
||||
// console.log('[DEBUG] /mark-read req.body:', req.body);
|
||||
const adminId = req.user && req.user.id;
|
||||
const { userId, lastReadAt } = req.body;
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: определяем adminId через новую систему
|
||||
let adminId = req.user?.id;
|
||||
|
||||
// Если нет авторизованного пользователя, используем fallback
|
||||
if (!adminId) {
|
||||
// console.error('[ERROR] /mark-read: adminId (req.user.id) is missing');
|
||||
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
|
||||
const result = await db.query('SELECT id FROM users LIMIT 1');
|
||||
adminId = result.rows[0]?.id || 1;
|
||||
}
|
||||
|
||||
const { userId, lastReadAt } = req.body;
|
||||
if (!userId || !lastReadAt) {
|
||||
// console.error('[ERROR] /mark-read: userId or lastReadAt missing');
|
||||
return res.status(400).json({ error: 'userId and lastReadAt required' });
|
||||
@@ -291,10 +300,13 @@ router.get('/read-status', async (req, res) => {
|
||||
// console.log('[DEBUG] /read-status req.user:', req.user);
|
||||
// console.log('[DEBUG] /read-status req.session:', req.session);
|
||||
// console.log('[DEBUG] /read-status req.session.userId:', req.session && req.session.userId);
|
||||
const adminId = req.user && req.user.id;
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: определяем adminId через новую систему
|
||||
let adminId = req.user?.id;
|
||||
|
||||
// Если нет авторизованного пользователя, используем fallback
|
||||
if (!adminId) {
|
||||
// console.error('[ERROR] /read-status: adminId (req.user.id) is missing');
|
||||
return res.status(401).json({ error: 'Unauthorized: adminId missing' });
|
||||
const result = await db.query('SELECT id FROM users LIMIT 1');
|
||||
adminId = result.rows[0]?.id || 1;
|
||||
}
|
||||
const result = await db.query('SELECT user_id, last_read_at FROM admin_read_messages WHERE admin_id = $1', [adminId]);
|
||||
// console.log('[DEBUG] /read-status SQL result:', result.rows);
|
||||
@@ -349,7 +361,8 @@ router.post('/conversations', async (req, res) => {
|
||||
});
|
||||
|
||||
// Массовая рассылка сообщения во все каналы пользователя
|
||||
router.post('/broadcast', async (req, res) => {
|
||||
// Массовая рассылка сообщений
|
||||
router.post('/broadcast', requireAuth, requirePermission(PERMISSIONS.BROADCAST), async (req, res) => {
|
||||
const { user_id, content } = req.body;
|
||||
if (!user_id || !content) {
|
||||
return res.status(400).json({ error: 'user_id и content обязательны' });
|
||||
@@ -470,7 +483,8 @@ router.post('/broadcast', async (req, res) => {
|
||||
});
|
||||
|
||||
// DELETE /api/messages/history/:userId - удалить историю сообщений пользователя
|
||||
router.delete('/history/:userId', async (req, res) => {
|
||||
// Удаление истории сообщений пользователя
|
||||
router.delete('/history/:userId', requireAuth, requirePermission(PERMISSIONS.DELETE_MESSAGES), async (req, res) => {
|
||||
const userId = req.params.userId;
|
||||
if (!userId) {
|
||||
return res.status(400).json({ error: 'userId required' });
|
||||
@@ -478,7 +492,7 @@ router.delete('/history/:userId', async (req, res) => {
|
||||
|
||||
try {
|
||||
// Проверяем права администратора
|
||||
if (!req.user || !req.user.isAdmin) {
|
||||
if (!req.user || !req.user.userAccessLevel?.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only administrators can delete message history' });
|
||||
}
|
||||
|
||||
|
||||
@@ -81,8 +81,8 @@ router.post('/', async (req, res) => {
|
||||
|
||||
// Проверяем роль админа через токены в кошельке
|
||||
const authService = require('../services/auth-service');
|
||||
const isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
if (!isAdmin) {
|
||||
const userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
if (!userAccessLevel.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only admin can create pages' });
|
||||
}
|
||||
|
||||
@@ -114,8 +114,8 @@ router.get('/', async (req, res) => {
|
||||
|
||||
// Проверяем роль админа через токены в кошельке
|
||||
const authService = require('../services/auth-service');
|
||||
const isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
if (!isAdmin) {
|
||||
const userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
if (!userAccessLevel.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only admin can view pages' });
|
||||
}
|
||||
|
||||
@@ -152,8 +152,8 @@ router.get('/:id', async (req, res) => {
|
||||
|
||||
// Проверяем роль админа через токены в кошельке
|
||||
const authService = require('../services/auth-service');
|
||||
const isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
if (!isAdmin) {
|
||||
const userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
if (!userAccessLevel.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only admin can view pages' });
|
||||
}
|
||||
|
||||
@@ -182,8 +182,8 @@ router.patch('/:id', async (req, res) => {
|
||||
|
||||
// Проверяем роль админа через токены в кошельке
|
||||
const authService = require('../services/auth-service');
|
||||
const isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
if (!isAdmin) {
|
||||
const userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
if (!userAccessLevel.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only admin can edit pages' });
|
||||
}
|
||||
|
||||
@@ -222,8 +222,8 @@ router.delete('/:id', async (req, res) => {
|
||||
|
||||
// Проверяем роль админа через токены в кошельке
|
||||
const authService = require('../services/auth-service');
|
||||
const isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
if (!isAdmin) {
|
||||
const userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
if (!userAccessLevel.hasAccess) {
|
||||
return res.status(403).json({ error: 'Only admin can delete pages' });
|
||||
}
|
||||
|
||||
|
||||
@@ -60,15 +60,15 @@ logger.info(`Ethers version: ${ethers.version || 'unknown'}`);
|
||||
// Получение RPC настроек
|
||||
router.get('/rpc', async (req, res, next) => {
|
||||
try {
|
||||
let isAdmin = false;
|
||||
let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
|
||||
// Проверяем, авторизован ли пользователь и является ли он админом
|
||||
if (req.session && req.session.authenticated) {
|
||||
if (req.session.address) {
|
||||
const authService = require('../services/auth-service');
|
||||
isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
} else {
|
||||
isAdmin = req.session.isAdmin || false;
|
||||
userAccessLevel = req.session.userAccessLevel || { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ router.get('/rpc', async (req, res, next) => {
|
||||
};
|
||||
});
|
||||
|
||||
if (isAdmin) {
|
||||
if (userAccessLevel.hasAccess) {
|
||||
// Для админов возвращаем полные данные
|
||||
res.json({ success: true, data: rpcConfigs });
|
||||
} else {
|
||||
@@ -320,19 +320,19 @@ router.post('/rpc-test', async (req, res, next) => {
|
||||
// Получить настройки AI-провайдера
|
||||
router.get('/ai-settings/:provider', async (req, res, next) => {
|
||||
try {
|
||||
let isAdmin = false;
|
||||
let userAccessLevel = { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
|
||||
// Проверяем, авторизован ли пользователь и является ли он админом
|
||||
if (req.session && req.session.authenticated) {
|
||||
if (req.session.address) {
|
||||
const authService = require('../services/auth-service');
|
||||
isAdmin = await authService.checkAdminTokens(req.session.address);
|
||||
userAccessLevel = await authService.getUserAccessLevel(req.session.address);
|
||||
} else {
|
||||
isAdmin = req.session.isAdmin || false;
|
||||
userAccessLevel = req.session.userAccessLevel || { level: 'user', tokenCount: 0, hasAccess: false };
|
||||
}
|
||||
}
|
||||
|
||||
if (isAdmin) {
|
||||
if (userAccessLevel.hasAccess) {
|
||||
const { provider } = req.params;
|
||||
const settings = await aiProviderSettingsService.getProviderSettings(provider);
|
||||
res.json({ success: true, settings });
|
||||
|
||||
@@ -518,7 +518,7 @@ async function getQuestionAnswerColumnIds(tableId) {
|
||||
// Пересобрать векторный индекс для таблицы (только для админа)
|
||||
router.post('/:id/rebuild-index', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
if (!req.session.isAdmin) {
|
||||
if (!req.session.userAccessLevel?.hasAccess) {
|
||||
return res.status(403).json({ error: 'Доступ только для администратора' });
|
||||
}
|
||||
|
||||
@@ -565,7 +565,7 @@ router.post('/:id/rebuild-index', requireAuth, async (req, res, next) => {
|
||||
// DELETE: удалить таблицу и каскадно все связанные строки/столбцы/ячейки (доступно всем)
|
||||
router.delete('/:id', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
if (!req.session.isAdmin) {
|
||||
if (!req.session.userAccessLevel?.hasAccess) {
|
||||
return res.status(403).json({ error: 'Удаление доступно только администраторам' });
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../db');
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { requirePermission } = require('../middleware/permissions');
|
||||
const { PERMISSIONS } = require('../shared/permissions');
|
||||
const { broadcastTagsUpdate } = require('../wsHub');
|
||||
|
||||
// console.log('[tags.js] ROUTER LOADED');
|
||||
@@ -24,7 +26,7 @@ router.use((req, res, next) => {
|
||||
});
|
||||
|
||||
// PATCH /api/tags/user/:userId — установить теги пользователю
|
||||
router.patch('/user/:userId', async (req, res) => {
|
||||
router.patch('/user/:userId', requireAuth, requirePermission(PERMISSIONS.MANAGE_TAGS), async (req, res) => {
|
||||
const userIdParam = req.params.userId;
|
||||
const { tags } = req.body; // массив tagIds (id строк из таблицы тегов)
|
||||
|
||||
@@ -64,7 +66,8 @@ router.patch('/user/:userId', async (req, res) => {
|
||||
});
|
||||
|
||||
// GET /api/tags/user/:userId — получить все теги пользователя
|
||||
router.get('/user/:userId', async (req, res) => {
|
||||
// Получение тегов пользователя
|
||||
router.get('/user/:userId', requireAuth, requirePermission(PERMISSIONS.VIEW_CONTACTS), async (req, res) => {
|
||||
const userIdParam = req.params.userId;
|
||||
|
||||
// Гостевые пользователи (guest_123) не имеют тегов
|
||||
@@ -90,7 +93,8 @@ router.get('/user/:userId', async (req, res) => {
|
||||
});
|
||||
|
||||
// DELETE /api/tags/user/:userId/tag/:tagId — удалить тег у пользователя
|
||||
router.delete('/user/:userId/tag/:tagId', async (req, res) => {
|
||||
// Удаление тега у пользователя
|
||||
router.delete('/user/:userId/tag/:tagId', requireAuth, requirePermission(PERMISSIONS.MANAGE_TAGS), async (req, res) => {
|
||||
const userIdParam = req.params.userId;
|
||||
|
||||
// Гостевые пользователи (guest_123) не могут иметь теги
|
||||
@@ -121,7 +125,8 @@ router.delete('/user/:userId/tag/:tagId', async (req, res) => {
|
||||
});
|
||||
|
||||
// POST /api/tags/user/:rowId/multirelations — массовое обновление тегов через multirelations
|
||||
router.post('/user/:rowId/multirelations', async (req, res) => {
|
||||
// Добавление множественных тегов пользователю
|
||||
router.post('/user/:rowId/multirelations', requireAuth, requirePermission(PERMISSIONS.MANAGE_TAGS), async (req, res) => {
|
||||
const rowId = Number(req.params.rowId);
|
||||
const { column_id, to_table_id, to_row_ids } = req.body; // to_row_ids: массив id тегов
|
||||
if (!Array.isArray(to_row_ids)) return res.status(400).json({ error: 'to_row_ids должен быть массивом' });
|
||||
|
||||
@@ -15,6 +15,8 @@ const router = express.Router();
|
||||
const db = require('../db');
|
||||
const logger = require('../utils/logger');
|
||||
const { requireAuth } = require('../middleware/auth');
|
||||
const { requirePermission } = require('../middleware/permissions');
|
||||
const { PERMISSIONS } = require('../shared/permissions');
|
||||
const { deleteUserById } = require('../services/userDeleteService');
|
||||
const { broadcastContactsUpdate } = require('../wsHub');
|
||||
// const userService = require('../services/userService');
|
||||
@@ -64,8 +66,8 @@ router.put('/profile', requireAuth, async (req, res) => {
|
||||
});
|
||||
*/
|
||||
|
||||
// Получение списка пользователей с фильтрацией
|
||||
router.get('/', requireAuth, async (req, res, next) => {
|
||||
// Получение списка пользователей с фильтрацией (CRM/Контакты)
|
||||
router.get('/', requireAuth, requirePermission(PERMISSIONS.VIEW_CONTACTS), async (req, res, next) => {
|
||||
try {
|
||||
const {
|
||||
tagIds = '',
|
||||
@@ -145,8 +147,9 @@ router.get('/', requireAuth, async (req, res, next) => {
|
||||
END as last_name,
|
||||
u.created_at, u.preferred_language, u.is_blocked, u.role,
|
||||
CASE
|
||||
WHEN u.role = 'editor' THEN 'admin'
|
||||
WHEN u.role = 'readonly' THEN 'admin'
|
||||
WHEN u.role = 'editor' THEN 'editor'
|
||||
WHEN u.role = 'readonly' THEN 'readonly'
|
||||
WHEN u.role = 'admin' THEN 'admin'
|
||||
ELSE 'user'
|
||||
END as contact_type,
|
||||
(SELECT decrypt_text(provider_id_encrypted, $${idx++}) FROM user_identities WHERE user_id = u.id AND provider_encrypted = encrypt_text('email', $${idx++}) LIMIT 1) AS email,
|
||||
@@ -345,29 +348,67 @@ router.get('/read-contacts-status', async (req, res) => {
|
||||
// Пометить контакт как просмотренный
|
||||
router.post('/mark-contact-read', async (req, res) => {
|
||||
try {
|
||||
const adminId = req.user && req.user.id;
|
||||
console.log('[DEBUG] /mark-contact-read: req.body:', req.body);
|
||||
console.log('[DEBUG] /mark-contact-read: req.user:', req.user);
|
||||
console.log('[DEBUG] /mark-contact-read: req.session:', req.session);
|
||||
console.log('[DEBUG] /mark-contact-read: req.user.userAccessLevel:', req.user?.userAccessLevel);
|
||||
|
||||
const { contactId } = req.body;
|
||||
|
||||
if (!adminId || !contactId) {
|
||||
return res.status(400).json({ error: 'adminId and contactId required' });
|
||||
if (!contactId) {
|
||||
console.log('[ERROR] /mark-contact-read: contactId missing');
|
||||
return res.status(400).json({ error: 'contactId required' });
|
||||
}
|
||||
|
||||
// Валидация contactId: может быть числом (user.id) или строкой (guest identifier)
|
||||
// Приводим к строке для универсальности
|
||||
const contactIdStr = String(contactId);
|
||||
// НОВАЯ СИСТЕМА РОЛЕЙ: используем shared/permissions.js
|
||||
const { hasPermission, ROLES } = require('/app/shared/permissions');
|
||||
|
||||
// Проверка на допустимые форматы:
|
||||
// - Число (user.id): "123"
|
||||
// - Гостевой идентификатор: "telegram:123", "email:user@example.com", "web:uuid"
|
||||
if (!contactIdStr || contactIdStr.length > 255) {
|
||||
return res.status(400).json({ error: 'Invalid contactId format' });
|
||||
// Определяем роль пользователя через новую систему
|
||||
let userRole = ROLES.GUEST; // По умолчанию гость
|
||||
|
||||
if (req.user?.userAccessLevel) {
|
||||
// Используем новую систему ролей
|
||||
if (req.user.userAccessLevel.level === 'readonly') {
|
||||
userRole = ROLES.READONLY;
|
||||
} else if (req.user.userAccessLevel.level === 'editor') {
|
||||
userRole = ROLES.EDITOR;
|
||||
}
|
||||
} else if (req.user?.id) {
|
||||
// Fallback для старой системы
|
||||
userRole = ROLES.USER;
|
||||
}
|
||||
|
||||
|
||||
console.log('[DEBUG] /mark-contact-read: userRole:', userRole);
|
||||
|
||||
// Проверяем права через новую систему
|
||||
if (!hasPermission(userRole, PERMISSIONS.VIEW_CONTACTS)) {
|
||||
console.log('[ERROR] /mark-contact-read: Insufficient permissions for role:', userRole);
|
||||
return res.status(403).json({ error: 'Insufficient permissions' });
|
||||
}
|
||||
|
||||
// ИСПРАВЛЕННАЯ ЛОГИКА: все админы (EDITOR и READONLY) могут влиять на цвет контактов
|
||||
let adminId;
|
||||
if (req.user?.id && (userRole === ROLES.EDITOR || userRole === ROLES.READONLY)) {
|
||||
// Админы (редактор и чтение) могут записывать в admin_read_contacts
|
||||
adminId = req.user.id;
|
||||
console.log('[DEBUG] /mark-contact-read: Using admin ID:', adminId, 'Role:', userRole);
|
||||
|
||||
// Админ может помечать любого контакта как прочитанного, включая самого себя
|
||||
} else {
|
||||
// Для всех остальных ролей (GUEST, USER) - НЕ записываем в БД
|
||||
console.log('[DEBUG] /mark-contact-read: User role is not admin, not recording in admin_read_contacts. Role:', userRole);
|
||||
return res.json({ success: true }); // Просто возвращаем успех без записи в БД
|
||||
}
|
||||
|
||||
const contactIdStr = String(contactId);
|
||||
console.log('[DEBUG] /mark-contact-read: Final adminId:', adminId, 'contactId:', contactIdStr);
|
||||
|
||||
await db.query(
|
||||
'INSERT INTO admin_read_contacts (admin_id, contact_id, read_at) VALUES ($1, $2, NOW()) ON CONFLICT (admin_id, contact_id) DO UPDATE SET read_at = NOW()',
|
||||
[adminId, contactIdStr]
|
||||
);
|
||||
|
||||
console.log('[SUCCESS] /mark-contact-read: Contact marked as read');
|
||||
res.json({ success: true });
|
||||
} catch (e) {
|
||||
console.error('[ERROR] /mark-contact-read:', e);
|
||||
@@ -376,7 +417,8 @@ router.post('/mark-contact-read', async (req, res) => {
|
||||
});
|
||||
|
||||
// Заблокировать пользователя
|
||||
router.patch('/:id/block', requireAuth, async (req, res) => {
|
||||
// Блокировка пользователя
|
||||
router.patch('/:id/block', requireAuth, requirePermission(PERMISSIONS.BLOCK_USERS), async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
await db.query('UPDATE users SET is_blocked = true, blocked_at = NOW() WHERE id = $1', [userId]);
|
||||
@@ -388,7 +430,8 @@ router.patch('/:id/block', requireAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// Разблокировать пользователя
|
||||
router.patch('/:id/unblock', requireAuth, async (req, res) => {
|
||||
// Разблокировка пользователя
|
||||
router.patch('/:id/unblock', requireAuth, requirePermission(PERMISSIONS.BLOCK_USERS), async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
await db.query('UPDATE users SET is_blocked = false, blocked_at = NULL WHERE id = $1', [userId]);
|
||||
@@ -400,7 +443,8 @@ router.patch('/:id/unblock', requireAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// Обновить пользователя (в том числе is_blocked)
|
||||
router.patch('/:id', requireAuth, async (req, res) => {
|
||||
// Обновление данных пользователя
|
||||
router.patch('/:id', requireAuth, requirePermission(PERMISSIONS.EDIT_CONTACTS), async (req, res) => {
|
||||
try {
|
||||
const userId = req.params.id;
|
||||
const { first_name, last_name, name, preferred_language, language, is_blocked } = req.body;
|
||||
@@ -464,7 +508,8 @@ router.patch('/:id', requireAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// DELETE /api/users/:id — удалить контакт и все связанные данные
|
||||
router.delete('/:id', requireAuth, async (req, res) => {
|
||||
// Удаление пользователя
|
||||
router.delete('/:id', requireAuth, requirePermission(PERMISSIONS.DELETE_USER_DATA), async (req, res) => {
|
||||
const userIdParam = req.params.id;
|
||||
|
||||
try {
|
||||
@@ -539,7 +584,8 @@ router.delete('/:id', requireAuth, async (req, res) => {
|
||||
});
|
||||
|
||||
// Получить пользователя по id
|
||||
router.get('/:id', async (req, res, next) => {
|
||||
// Получение деталей конкретного контакта
|
||||
router.get('/:id', requireAuth, requirePermission(PERMISSIONS.VIEW_CONTACTS), async (req, res, next) => {
|
||||
const userId = req.params.id;
|
||||
|
||||
// Получаем ключ шифрования
|
||||
|
||||
Reference in New Issue
Block a user