feat: новая функция
This commit is contained in:
@@ -1,130 +0,0 @@
|
||||
# 🚀 Экспорт шаблона приложения в GitHub
|
||||
|
||||
## Цель
|
||||
Экспортировать все образы и тома как файлы в GitHub репозиторий для создания полного шаблона приложения.
|
||||
|
||||
## 📋 Команды для экспорта
|
||||
|
||||
### 1. Создать папки для данных
|
||||
```bash
|
||||
mkdir -p ./docker-data/images
|
||||
mkdir -p ./docker-data/volumes
|
||||
```
|
||||
|
||||
### 2. Экспортировать образы в файлы
|
||||
```bash
|
||||
# Backend образ
|
||||
docker save digital_legal_entitydle-backend:latest -o ./docker-data/images/backend.tar
|
||||
|
||||
# Frontend образ
|
||||
docker save digital_legal_entitydle-frontend:latest -o ./docker-data/images/frontend.tar
|
||||
|
||||
# Vector Search образ
|
||||
docker save digital_legal_entitydle-vector-search:latest -o ./docker-data/images/vector-search.tar
|
||||
|
||||
# Ollama образ
|
||||
docker save digital_legal_entitydle-ollama:latest -o ./docker-data/images/ollama.tar
|
||||
|
||||
# WebSSH Agent образ
|
||||
docker save digital_legal_entitydle-webssh-agent:latest -o ./docker-data/images/webssh-agent.tar
|
||||
```
|
||||
|
||||
### 3. Экспортировать тома в файлы
|
||||
```bash
|
||||
# PostgreSQL данные
|
||||
docker run --rm -v digital_legal_entitydle_postgres_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/postgres_data.tar.gz -C /source .
|
||||
|
||||
# Ollama данные
|
||||
docker run --rm -v digital_legal_entitydle_ollama_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/ollama_data.tar.gz -C /source .
|
||||
|
||||
# Vector Search данные
|
||||
docker run --rm -v digital_legal_entitydle_vector_search_data:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/vector_search_data.tar.gz -C /source .
|
||||
|
||||
# Backend node_modules
|
||||
docker run --rm -v digital_legal_entitydle_backend_node_modules:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/backend_node_modules.tar.gz -C /source .
|
||||
|
||||
# Frontend node_modules
|
||||
docker run --rm -v digital_legal_entitydle_frontend_node_modules:/source -v $(pwd)/docker-data/volumes:/backup alpine tar czf /backup/frontend_node_modules.tar.gz -C /source .
|
||||
```
|
||||
|
||||
### 4. Загрузить все в GitHub
|
||||
```bash
|
||||
# Добавить файлы в git
|
||||
git add docker-data/
|
||||
|
||||
# Закоммитить
|
||||
git commit -m "Add exported images and volumes"
|
||||
|
||||
# Запушить в репозиторий
|
||||
git push
|
||||
```
|
||||
|
||||
## 📊 Результат
|
||||
|
||||
После выполнения всех команд в репозитории будут:
|
||||
- ✅ Все образы как файлы (.tar)
|
||||
- ✅ Все тома как файлы (.tar.gz)
|
||||
- ✅ Полный шаблон приложения
|
||||
|
||||
## 🚀 Использование шаблона
|
||||
|
||||
### Для пользователей:
|
||||
```bash
|
||||
# Клонировать репозиторий
|
||||
git clone https://github.com/VC-HB3-Accelerator/DLE.git
|
||||
cd DLE
|
||||
|
||||
# Импортировать образы
|
||||
docker load -i docker-data/images/backend.tar
|
||||
docker load -i docker-data/images/frontend.tar
|
||||
docker load -i docker-data/images/vector-search.tar
|
||||
docker load -i docker-data/images/ollama.tar
|
||||
docker load -i docker-data/images/webssh-agent.tar
|
||||
|
||||
# Импортировать тома
|
||||
docker volume create digital_legal_entitydle_postgres_data
|
||||
docker run --rm -v digital_legal_entitydle_postgres_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/postgres_data.tar.gz -C /target
|
||||
|
||||
docker volume create digital_legal_entitydle_ollama_data
|
||||
docker run --rm -v digital_legal_entitydle_ollama_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/ollama_data.tar.gz -C /target
|
||||
|
||||
docker volume create digital_legal_entitydle_vector_search_data
|
||||
docker run --rm -v digital_legal_entitydle_vector_search_data:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/vector_search_data.tar.gz -C /target
|
||||
|
||||
docker volume create digital_legal_entitydle_backend_node_modules
|
||||
docker run --rm -v digital_legal_entitydle_backend_node_modules:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/backend_node_modules.tar.gz -C /target
|
||||
|
||||
docker volume create digital_legal_entitydle_frontend_node_modules
|
||||
docker run --rm -v digital_legal_entitydle_frontend_node_modules:/target -v $(pwd)/docker-data/volumes:/backup alpine tar xzf /backup/frontend_node_modules.tar.gz -C /target
|
||||
|
||||
# Запустить приложение
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
## ⚠️ Важные замечания
|
||||
|
||||
1. **Размер файлов**: Образы могут быть большими (несколько GB)
|
||||
2. **Время загрузки**: Зависит от размера файлов и скорости интернета
|
||||
3. **Место на диске**: Убедитесь, что достаточно места для всех файлов
|
||||
|
||||
## 📁 Структура после экспорта
|
||||
|
||||
```
|
||||
docker-data/
|
||||
├── images/
|
||||
│ ├── backend.tar
|
||||
│ ├── frontend.tar
|
||||
│ ├── vector-search.tar
|
||||
│ ├── ollama.tar
|
||||
│ └── webssh-agent.tar
|
||||
└── volumes/
|
||||
├── postgres_data.tar.gz
|
||||
├── ollama_data.tar.gz
|
||||
├── vector_search_data.tar.gz
|
||||
├── backend_node_modules.tar.gz
|
||||
└── frontend_node_modules.tar.gz
|
||||
```
|
||||
|
||||
## ✅ Готово!
|
||||
|
||||
После выполнения всех команд у вас будет полный шаблон приложения в GitHub репозитории, который можно клонировать и запускать на любом устройстве.
|
||||
41
README.md
41
README.md
@@ -44,18 +44,55 @@ docker-compose up -d
|
||||
```
|
||||
|
||||
### Доступ к приложению
|
||||
|
||||
#### Разработка (dev)
|
||||
- **Frontend**: http://localhost:5173
|
||||
- **Backend API**: http://localhost:8000
|
||||
|
||||
#### Продакшн (production)
|
||||
- **Frontend**: http://localhost:9000 (HTTP) или https://localhost:9443 (HTTPS)
|
||||
- **Backend API**: http://localhost:9000/api (через nginx proxy)
|
||||
|
||||
## 🔧 Управление
|
||||
|
||||
### Запуск
|
||||
```
|
||||
|
||||
#### Продакшн (production)
|
||||
```bash
|
||||
docker-compose up -d
|
||||
# Пересборка образов
|
||||
docker-compose build --no-cache
|
||||
|
||||
# Запуск продакшн-сервисов
|
||||
NODE_ENV=production docker-compose --profile production up -d
|
||||
|
||||
# Проверка
|
||||
docker-compose ps
|
||||
curl http://localhost:9000/api/health
|
||||
```
|
||||
|
||||
### Остановка
|
||||
```bash
|
||||
docker-compose down
|
||||
docker-compose-down
|
||||
```
|
||||
|
||||
### Полезные команды
|
||||
```bash
|
||||
# Просмотр логов
|
||||
docker-compose logs -f backend
|
||||
docker-compose logs -f frontend-nginx
|
||||
|
||||
# Перезапуск сервиса
|
||||
docker-compose restart backend
|
||||
docker-compose restart frontend-nginx
|
||||
|
||||
# Пересборка конкретного сервиса
|
||||
docker-compose build --no-cache backend
|
||||
docker-compose build --no-cache frontend-nginx
|
||||
|
||||
# Просмотр статуса
|
||||
docker-compose ps
|
||||
docker ps # Все контейнеры в системе
|
||||
```
|
||||
|
||||
## 📝 Лицензия
|
||||
|
||||
@@ -22,8 +22,7 @@ README*
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Зависимости (будут установлены в контейнере)
|
||||
node_modules/
|
||||
# Логи установки
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
@@ -16,6 +16,7 @@ const cors = require('cors');
|
||||
const session = require('express-session');
|
||||
const sessionConfig = require('./config/session');
|
||||
const logger = require('./utils/logger');
|
||||
const rateLimit = require('express-rate-limit');
|
||||
// const csurf = require('csurf'); // Закомментировано, так как не используется
|
||||
const errorHandler = require('./middleware/errorHandler');
|
||||
// const { version } = require('./package.json'); // Закомментировано, так как не используется
|
||||
@@ -115,14 +116,21 @@ app.set('host', '0.0.0.0');
|
||||
app.set('port', process.env.PORT || 8000);
|
||||
|
||||
// Настройка CORS
|
||||
const corsOrigins = process.env.NODE_ENV === 'production'
|
||||
? [
|
||||
'http://localhost:9000', // Локальный Docker nginx
|
||||
'https://localhost:9443', // Локальный Docker nginx HTTPS
|
||||
// Добавьте ваш продакшн домен здесь для VDS
|
||||
// 'https://yourdomain.com',
|
||||
]
|
||||
: [
|
||||
'http://localhost:5173', // Vite dev server
|
||||
'http://127.0.0.1:5173',
|
||||
];
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: [
|
||||
'http://localhost:5173',
|
||||
'http://127.0.0.1:5173',
|
||||
'https://hb3-accelerator.com',
|
||||
'https://www.hb3-accelerator.com',
|
||||
],
|
||||
origin: corsOrigins,
|
||||
credentials: true,
|
||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
||||
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'],
|
||||
@@ -171,6 +179,36 @@ app.use((req, res, next) => {
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// Определяем режим работы
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
// Rate limiting
|
||||
const limiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 минут
|
||||
max: isProduction ? 100 : 1000, // 100 запросов в продакшне, 1000 в dev
|
||||
message: {
|
||||
error: 'Слишком много запросов, попробуйте позже',
|
||||
retryAfter: '15 минут'
|
||||
},
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Применяем rate limiting ко всем запросам
|
||||
app.use(limiter);
|
||||
|
||||
// Строгий rate limiting для чувствительных эндпоинтов
|
||||
const strictLimiter = rateLimit({
|
||||
windowMs: 15 * 60 * 1000, // 15 минут
|
||||
max: 10, // 10 попыток
|
||||
message: {
|
||||
error: 'Превышен лимит попыток, попробуйте позже',
|
||||
retryAfter: '15 минут'
|
||||
},
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
});
|
||||
|
||||
// Статическая раздача загруженных файлов (для dev и prod)
|
||||
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||
app.use('/api/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||
@@ -178,14 +216,26 @@ app.use('/api/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||
// Настройка безопасности
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: false, // Отключаем CSP для разработки
|
||||
contentSecurityPolicy: isProduction ? {
|
||||
directives: {
|
||||
defaultSrc: ["'self'"],
|
||||
styleSrc: ["'self'", "'unsafe-inline'"],
|
||||
scriptSrc: ["'self'"],
|
||||
imgSrc: ["'self'", "data:", "https:"],
|
||||
connectSrc: ["'self'", "ws:", "wss:"],
|
||||
fontSrc: ["'self'"],
|
||||
objectSrc: ["'none'"],
|
||||
mediaSrc: ["'self'"],
|
||||
frameSrc: ["'none'"],
|
||||
},
|
||||
} : false, // Отключаем CSP для разработки
|
||||
})
|
||||
);
|
||||
|
||||
// Маршруты API
|
||||
app.use('/api/tables', tablesRoutes); // ДОЛЖНО БЫТЬ ВЫШЕ!
|
||||
// app.use('/api', identitiesRoutes);
|
||||
app.use('/api/auth', authRoutes);
|
||||
app.use('/api/auth', strictLimiter, authRoutes); // Строгий rate limiting для аутентификации
|
||||
app.use('/api/users', usersRoutes);
|
||||
app.use('/api/chat', chatRoutes);
|
||||
app.use('/api/admin', adminRoutes);
|
||||
@@ -195,10 +245,10 @@ app.use('/api/kpp', kppRoutes); // Добавленное использован
|
||||
app.use('/api/geocoding', geocodingRoutes); // Добавленное использование роута
|
||||
|
||||
app.use('/api/dle-v2', dleV2Routes); // Добавляем маршрут DLE v2
|
||||
app.use('/api/settings', settingsRoutes); // Добавляем маршрут настроек
|
||||
app.use('/api/settings', strictLimiter, settingsRoutes); // Строгий rate limiting для настроек
|
||||
app.use('/api/countries', countriesRoutes); // Добавляем маршрут стран
|
||||
app.use('/api/russian-classifiers', russianClassifiersRoutes); // Добавляем маршрут российских классификаторов
|
||||
app.use('/api/ollama', ollamaRoutes); // Добавляем маршрут Ollama
|
||||
app.use('/api/ollama', strictLimiter, ollamaRoutes); // Строгий rate limiting для Ollama
|
||||
app.use('/api/ai-queue', aiQueueRoutes); // Добавляем маршрут AI Queue
|
||||
app.use('/api/tags', tagsRoutes); // Добавляем маршрут тегов
|
||||
app.use('/api/blockchain', blockchainRoutes); // Добавляем маршрут blockchain
|
||||
|
||||
@@ -24,6 +24,8 @@ function setPoolChangeCallback(cb) {
|
||||
let sessionMiddleware = createSessionMiddleware();
|
||||
|
||||
function createSessionMiddleware() {
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
return session({
|
||||
store: new pgSession({
|
||||
pool: db.getPool(),
|
||||
@@ -36,8 +38,8 @@ function createSessionMiddleware() {
|
||||
cookie: {
|
||||
maxAge: 30 * 24 * 60 * 60 * 1000,
|
||||
httpOnly: true,
|
||||
secure: false,
|
||||
sameSite: 'lax',
|
||||
secure: false, // false для локального Docker (HTTP)
|
||||
sameSite: 'lax', // lax для локального Docker
|
||||
path: '/',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -787,12 +787,16 @@ router.get('/encryption-key/status', requireAdmin, async (req, res) => {
|
||||
|
||||
const exists = fs.existsSync(keyPath);
|
||||
|
||||
let key = null;
|
||||
// Возвращаем только метаданные без содержимого ключа
|
||||
let checksum = null;
|
||||
if (exists) {
|
||||
try {
|
||||
key = fs.readFileSync(keyPath, 'utf8').trim();
|
||||
const data = fs.readFileSync(keyPath);
|
||||
// лёгкая хэш-сумма для проверки целостности без раскрытия ключа
|
||||
const crypto = require('crypto');
|
||||
checksum = crypto.createHash('sha256').update(data).digest('hex');
|
||||
} catch (error) {
|
||||
logger.error('Ошибка чтения ключа:', error);
|
||||
logger.error('Ошибка чтения ключа для метаданных:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -800,7 +804,7 @@ router.get('/encryption-key/status', requireAdmin, async (req, res) => {
|
||||
success: true,
|
||||
exists,
|
||||
path: keyPath,
|
||||
key: key
|
||||
checksum
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error('Ошибка проверки статуса ключа шифрования:', error);
|
||||
|
||||
@@ -1,48 +1,10 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const https = require('https');
|
||||
const { promisify } = require('util');
|
||||
const dns = require('dns');
|
||||
|
||||
const resolve4 = promisify(dns.resolve4);
|
||||
|
||||
const SSH_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.ssh');
|
||||
const DEFAULT_KEY_PATH = path.join(SSH_DIR, 'id_rsa');
|
||||
const DEFAULT_PUB_KEY_PATH = path.join(SSH_DIR, 'id_rsa.pub');
|
||||
|
||||
// Helper to read SSH key
|
||||
const readSshKey = (keyPath) => {
|
||||
try {
|
||||
return fs.readFileSync(keyPath, 'utf8');
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// GET /api/ssh-key - Get existing SSH private key
|
||||
router.get('/ssh-key', (req, res) => {
|
||||
const privateKey = readSshKey(DEFAULT_KEY_PATH);
|
||||
const publicKey = readSshKey(DEFAULT_PUB_KEY_PATH);
|
||||
|
||||
if (privateKey) {
|
||||
res.json({ success: true, sshKey: privateKey, publicKey: publicKey, keyType: 'rsa' });
|
||||
} else {
|
||||
res.status(404).json({ success: false, message: 'SSH private key not found' });
|
||||
}
|
||||
});
|
||||
|
||||
// GET /api/ssh-key/public - Get existing SSH public key
|
||||
router.get('/ssh-key/public', (req, res) => {
|
||||
const publicKey = readSshKey(DEFAULT_PUB_KEY_PATH);
|
||||
|
||||
if (publicKey) {
|
||||
res.json({ success: true, publicKey: publicKey, keyType: 'rsa' });
|
||||
} else {
|
||||
res.status(404).json({ success: false, message: 'SSH public key not found' });
|
||||
}
|
||||
});
|
||||
// Удалено: эндпоинты выдачи приватного/публичного SSH-ключа
|
||||
|
||||
// GET /api/dns-check/:domain - Check DNS and get IP address
|
||||
router.get('/dns-check/:domain', async (req, res) => {
|
||||
|
||||
279
backend/shared/permissions.js
Normal file
279
backend/shared/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
# Проверка схемы базы данных
|
||||
|
||||
## Таблица `users`
|
||||
```sql
|
||||
CREATE TABLE users (
|
||||
id SERIAL PRIMARY KEY,
|
||||
username VARCHAR(255),
|
||||
email VARCHAR(255) UNIQUE,
|
||||
address VARCHAR(255) UNIQUE,
|
||||
first_name_encrypted TEXT,
|
||||
last_name_encrypted TEXT,
|
||||
status VARCHAR(50) DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
role user_role DEFAULT 'user',
|
||||
first_name VARCHAR(255),
|
||||
last_name VARCHAR(255),
|
||||
preferred_language JSONB,
|
||||
is_blocked BOOLEAN DEFAULT false,
|
||||
blocked_at TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `username` - VARCHAR(255)
|
||||
- `email` - VARCHAR(255) UNIQUE
|
||||
- `address` - VARCHAR(255) UNIQUE
|
||||
- `first_name_encrypted` - TEXT (зашифрованное)
|
||||
- `last_name_encrypted` - TEXT (зашифрованное)
|
||||
- `status` - VARCHAR(50) DEFAULT 'active'
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
- `updated_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
- `role` - user_role DEFAULT 'user'
|
||||
- `first_name` - VARCHAR(255) (незашифрованное)
|
||||
- `last_name` - VARCHAR(255) (незашифрованное)
|
||||
- `preferred_language` - JSONB
|
||||
- `is_blocked` - BOOLEAN DEFAULT false
|
||||
- `blocked_at` - TIMESTAMP
|
||||
|
||||
## Таблица `conversations`
|
||||
```sql
|
||||
CREATE TABLE conversations (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
title VARCHAR(255),
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
conversation_type VARCHAR(50) DEFAULT 'user_chat'
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `user_id` - INTEGER REFERENCES users(id)
|
||||
- `title` - VARCHAR(255) (НЕ зашифрованное!)
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
- `updated_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
- `conversation_type` - VARCHAR(50) DEFAULT 'user_chat'
|
||||
|
||||
## Таблица `messages`
|
||||
```sql
|
||||
CREATE TABLE messages (
|
||||
id SERIAL PRIMARY KEY,
|
||||
conversation_id INTEGER REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
sender_type_encrypted TEXT NOT NULL,
|
||||
sender_id INTEGER,
|
||||
content_encrypted TEXT,
|
||||
channel_encrypted TEXT NOT NULL,
|
||||
role_encrypted TEXT NOT NULL DEFAULT 'user',
|
||||
direction_encrypted TEXT,
|
||||
metadata JSONB,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
tokens_used INTEGER DEFAULT 0,
|
||||
is_processed BOOLEAN DEFAULT false,
|
||||
role VARCHAR(20) NOT NULL DEFAULT 'user',
|
||||
attachment_filename TEXT,
|
||||
attachment_mimetype TEXT,
|
||||
attachment_size BIGINT,
|
||||
attachment_data BYTEA,
|
||||
direction VARCHAR(8),
|
||||
message_type VARCHAR(20) DEFAULT 'public'
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `conversation_id` - INTEGER REFERENCES conversations(id)
|
||||
- `sender_type_encrypted` - TEXT NOT NULL (зашифрованное)
|
||||
- `sender_id` - INTEGER
|
||||
- `content_encrypted` - TEXT (зашифрованное)
|
||||
- `channel_encrypted` - TEXT NOT NULL (зашифрованное)
|
||||
- `role_encrypted` - TEXT NOT NULL DEFAULT 'user' (зашифрованное)
|
||||
- `direction_encrypted` - TEXT (зашифрованное)
|
||||
- `metadata` - JSONB
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
- `user_id` - INTEGER REFERENCES users(id)
|
||||
- `tokens_used` - INTEGER DEFAULT 0
|
||||
- `is_processed` - BOOLEAN DEFAULT false
|
||||
- `role` - VARCHAR(20) NOT NULL DEFAULT 'user' (НЕ зашифрованное!)
|
||||
- `attachment_filename` - TEXT
|
||||
- `attachment_mimetype` - TEXT
|
||||
- `attachment_size` - BIGINT
|
||||
- `attachment_data` - BYTEA
|
||||
- `direction` - VARCHAR(8) (НЕ зашифрованное!)
|
||||
- `message_type` - VARCHAR(20) DEFAULT 'public'
|
||||
|
||||
**Триггеры:**
|
||||
- `trg_set_message_user_id` - автоматически устанавливает user_id
|
||||
|
||||
## Таблица `conversation_participants`
|
||||
```sql
|
||||
CREATE TABLE conversation_participants (
|
||||
id SERIAL PRIMARY KEY,
|
||||
conversation_id INTEGER REFERENCES conversations(id) ON DELETE CASCADE,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(conversation_id, user_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `conversation_id` - INTEGER REFERENCES conversations(id)
|
||||
- `user_id` - INTEGER REFERENCES users(id)
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `id`
|
||||
- UNIQUE CONSTRAINT на `(conversation_id, user_id)`
|
||||
- Индекс на `conversation_id`
|
||||
- Индекс на `user_id`
|
||||
|
||||
## Таблица `admin_read_messages`
|
||||
```sql
|
||||
CREATE TABLE admin_read_messages (
|
||||
admin_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
last_read_at TIMESTAMP NOT NULL,
|
||||
PRIMARY KEY (admin_id, user_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `admin_id` - INTEGER NOT NULL REFERENCES users(id) (админ)
|
||||
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
|
||||
- `last_read_at` - TIMESTAMP NOT NULL (время последнего прочтения)
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `(admin_id, user_id)`
|
||||
|
||||
## Таблица `admin_read_contacts`
|
||||
```sql
|
||||
CREATE TABLE admin_read_contacts (
|
||||
admin_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
contact_id TEXT NOT NULL,
|
||||
read_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
PRIMARY KEY (admin_id, contact_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `admin_id` - INTEGER NOT NULL REFERENCES users(id) (админ)
|
||||
- `contact_id` - TEXT NOT NULL (ID контакта)
|
||||
- `read_at` - TIMESTAMP NOT NULL DEFAULT NOW() (время прочтения)
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `(admin_id, contact_id)`
|
||||
- Индекс на `admin_id`
|
||||
- Индекс на `contact_id`
|
||||
|
||||
## Таблица `user_identities`
|
||||
```sql
|
||||
CREATE TABLE user_identities (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
|
||||
provider_encrypted TEXT NOT NULL,
|
||||
provider_id_encrypted TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `user_id` - INTEGER REFERENCES users(id) (пользователь)
|
||||
- `provider_encrypted` - TEXT NOT NULL (зашифрованный провайдер)
|
||||
- `provider_id_encrypted` - TEXT NOT NULL (зашифрованный ID провайдера)
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `id`
|
||||
- Индекс на `user_id`
|
||||
|
||||
## Таблица `user_preferences`
|
||||
```sql
|
||||
CREATE TABLE user_preferences (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
preference_key VARCHAR(50) NOT NULL,
|
||||
preference_value TEXT,
|
||||
metadata JSONB DEFAULT '{}',
|
||||
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||
UNIQUE(user_id, preference_key)
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
|
||||
- `preference_key` - VARCHAR(50) NOT NULL (ключ настройки)
|
||||
- `preference_value` - TEXT (значение настройки)
|
||||
- `metadata` - JSONB DEFAULT '{}' (метаданные)
|
||||
- `created_at` - TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
- `updated_at` - TIMESTAMP NOT NULL DEFAULT NOW()
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `id`
|
||||
- Индекс на `user_id`
|
||||
- UNIQUE CONSTRAINT на `(user_id, preference_key)`
|
||||
|
||||
## Таблица `user_tag_links`
|
||||
```sql
|
||||
CREATE TABLE user_tag_links (
|
||||
id SERIAL PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
tag_id INTEGER NOT NULL REFERENCES user_rows(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE(user_id, tag_id)
|
||||
);
|
||||
```
|
||||
|
||||
**Колонки:**
|
||||
- `id` - SERIAL PRIMARY KEY
|
||||
- `user_id` - INTEGER NOT NULL REFERENCES users(id) (пользователь)
|
||||
- `tag_id` - INTEGER NOT NULL REFERENCES user_rows(id) (тег)
|
||||
- `created_at` - TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
|
||||
**Индексы:**
|
||||
- PRIMARY KEY на `id`
|
||||
- Индекс на `user_id`
|
||||
- Индекс на `tag_id`
|
||||
- UNIQUE CONSTRAINT на `(user_id, tag_id)`
|
||||
|
||||
## Анализ проблем в коде
|
||||
|
||||
Теперь, имея полную схему базы данных, давайте проверим код на соответствие:
|
||||
@@ -24,8 +24,6 @@ services:
|
||||
- POSTGRES_DB=${DB_NAME:-dapp_db}
|
||||
- POSTGRES_USER=${DB_USER:-dapp_user}
|
||||
- POSTGRES_PASSWORD=${DB_PASSWORD:-dapp_password}
|
||||
ports:
|
||||
- '5432:5432' # Открываем доступ к базе данных извне для разработки
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
@@ -138,7 +136,7 @@ services:
|
||||
- ./ssl:/app/ssl
|
||||
- ./shared:/app/shared:ro
|
||||
environment:
|
||||
- NODE_ENV=${NODE_ENV:-development}
|
||||
- NODE_ENV=${NODE_ENV:-production}
|
||||
- PORT=${PORT:-8000}
|
||||
- DB_HOST=postgres
|
||||
- DB_PORT=5432
|
||||
@@ -150,11 +148,12 @@ services:
|
||||
- OLLAMA_BASE_URL=http://ollama:11434
|
||||
- OLLAMA_MODEL=${OLLAMA_MODEL:-qwen2.5:7b}
|
||||
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_MODEL:-qwen2.5:7b}
|
||||
- FRONTEND_URL=http://localhost:5173
|
||||
# FRONTEND_URL настраивается в коде, не через env
|
||||
- VECTOR_SEARCH_URL=http://vector-search:8001
|
||||
# Factory адреса теперь хранятся в базе данных
|
||||
ports:
|
||||
- '8000:8000'
|
||||
# Убираем порты для продакшна - доступ только через nginx
|
||||
# ports:
|
||||
# - '8000:8000'
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
healthcheck:
|
||||
@@ -164,6 +163,7 @@ services:
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
frontend:
|
||||
profiles: ["dev"] # Только для разработки
|
||||
build:
|
||||
context: ./frontend
|
||||
dockerfile: Dockerfile
|
||||
@@ -204,37 +204,33 @@ services:
|
||||
- "9000:80" # Frontend nginx (для production на VDS)
|
||||
- "9443:443" # HTTPS порт для production на VDS
|
||||
environment:
|
||||
- DOMAIN=${DOMAIN:-localhost:9000}
|
||||
- DOMAIN=${DOMAIN:-production.local}
|
||||
- BACKEND_CONTAINER=dapp-backend
|
||||
depends_on:
|
||||
- backend
|
||||
|
||||
|
||||
|
||||
# SSH Key Server для безопасной передачи ключей
|
||||
ssh-key-server:
|
||||
image: node:20-slim
|
||||
container_name: dapp-ssh-key-server
|
||||
restart: unless-stopped
|
||||
dns:
|
||||
- 1.1.1.1 # Cloudflare (приватность)
|
||||
- 9.9.9.9 # Quad9 (безопасность + блокировка вредоносных доменов)
|
||||
- 8.8.8.8 # Google (надежность, fallback)
|
||||
volumes:
|
||||
- ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
|
||||
- ./ssl:/app/ssl
|
||||
- ~/.ssh:/root/.ssh:rw
|
||||
ports:
|
||||
- '3001:3001'
|
||||
command: node /app/ssh-key-server.js
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3001/ssh-key', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
# SSH Key Server отключен по безопасности (оставлен пример профиля dev при необходимости)
|
||||
# ssh-key-server:
|
||||
# profiles: ["dev"]
|
||||
# image: node:20-slim
|
||||
# container_name: dapp-ssh-key-server
|
||||
# restart: unless-stopped
|
||||
# dns:
|
||||
# - 1.1.1.1
|
||||
# - 9.9.9.9
|
||||
# - 8.8.8.8
|
||||
# volumes:
|
||||
# - ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
|
||||
# - ./ssl:/app/ssl:ro
|
||||
# - ~/.ssh:/root/.ssh:ro
|
||||
# command: node /app/ssh-key-server.js
|
||||
# # Порт намеренно не публикуется, без healthcheck
|
||||
|
||||
# WebSSH Agent для настройки VDS
|
||||
webssh-agent:
|
||||
profiles: ["dev"] # Только для разработки
|
||||
build:
|
||||
context: ./webssh-agent
|
||||
dockerfile: Dockerfile
|
||||
|
||||
@@ -22,8 +22,7 @@ README*
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Зависимости (будут установлены в контейнере)
|
||||
node_modules/
|
||||
# Логи установки
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
@@ -9,7 +9,7 @@ echo " DOMAIN: $DOMAIN"
|
||||
echo " BACKEND_CONTAINER: $BACKEND_CONTAINER"
|
||||
|
||||
# Выбор конфигурации в зависимости от домена
|
||||
if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$'; then
|
||||
if echo "$DOMAIN" | grep -qE '^localhost(:[0-9]+)?$|^production\.local$'; then
|
||||
echo " Режим: ЛОКАЛЬНАЯ РАЗРАБОТКА (без SSL)"
|
||||
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
|
||||
else
|
||||
|
||||
279
frontend/shared/permissions.js
Normal file
279
frontend/shared/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ import { useTagsWebSocket } from '../composables/useTagsWebSocket';
|
||||
import { useContactsAndMessagesWebSocket } from '../composables/useContactsWebSocket';
|
||||
import { usePermissions } from '@/composables/usePermissions';
|
||||
import { useAuthContext } from '@/composables/useAuth';
|
||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS } from './permissions.js';
|
||||
import api from '../api/axios';
|
||||
import { sendMessage, getPrivateUnreadCount } from '../services/messagesService';
|
||||
import { useRoles } from '@/composables/useRoles';
|
||||
|
||||
279
frontend/src/components/permissions.js
Normal file
279
frontend/src/components/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
279
frontend/src/composables/permissions.js
Normal file
279
frontend/src/composables/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
import { computed } from 'vue';
|
||||
import { useAuthContext } from './useAuth';
|
||||
import { PERMISSIONS, ROLES, hasPermission as checkPermission, getRoleDescription } from '/app/shared/permissions';
|
||||
import { PERMISSIONS, ROLES, hasPermission as checkPermission, getRoleDescription } from './permissions.js';
|
||||
|
||||
/**
|
||||
* Composable для работы с правами доступа
|
||||
|
||||
@@ -19,7 +19,7 @@ const SettingsInterfaceView = () => import('../views/settings/Interface/Interfac
|
||||
|
||||
import axios from 'axios';
|
||||
import { setToStorage } from '../utils/storage.js';
|
||||
import { PERMISSIONS, hasPermission } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS, hasPermission } from './permissions.js';
|
||||
|
||||
// console.log('router/index.js: Script loaded');
|
||||
|
||||
|
||||
279
frontend/src/router/permissions.js
Normal file
279
frontend/src/router/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
279
frontend/src/shared/permissions.js
Normal file
279
frontend/src/shared/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import BaseLayout from '../components/BaseLayout.vue';
|
||||
import pagesService from '../services/pagesService';
|
||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS } from './permissions.js';
|
||||
import { useAuthContext } from '../composables/useAuth';
|
||||
import { usePermissions } from '../composables/usePermissions';
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ import messagesService from '../../services/messagesService.js';
|
||||
import { getPublicMessages, getConversationByUserId, sendMessage, getPersonalChatHistory } from '../../services/messagesService.js';
|
||||
import { useAuthContext } from '@/composables/useAuth';
|
||||
import { usePermissions } from '@/composables/usePermissions';
|
||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS } from './permissions.js';
|
||||
import { useContactsAndMessagesWebSocket } from '@/composables/useContactsWebSocket';
|
||||
const { canEditContacts, canDeleteData, canManageTags, canBlockUsers, canSendToUsers, canGenerateAI, canViewContacts, hasPermission } = usePermissions();
|
||||
const { address, userId: currentUserId } = useAuthContext();
|
||||
|
||||
279
frontend/src/views/contacts/permissions.js
Normal file
279
frontend/src/views/contacts/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ import BaseLayout from '../../components/BaseLayout.vue';
|
||||
import pagesService from '../../services/pagesService';
|
||||
import { useAuthContext } from '../../composables/useAuth';
|
||||
import { usePermissions } from '../../composables/usePermissions';
|
||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS } from './permissions.js';
|
||||
|
||||
const props = defineProps({
|
||||
isAuthenticated: { type: Boolean, default: false },
|
||||
|
||||
@@ -55,7 +55,7 @@ import pagesService from '../../services/pagesService';
|
||||
import api from '../../api/axios';
|
||||
import { useAuthContext } from '../../composables/useAuth';
|
||||
import { usePermissions } from '../../composables/usePermissions';
|
||||
import { PERMISSIONS as SHARED_PERMISSIONS } from '/app/shared/permissions.js';
|
||||
import { PERMISSIONS as SHARED_PERMISSIONS } from './permissions.js';
|
||||
|
||||
const props = defineProps({
|
||||
isAuthenticated: { type: Boolean, default: false },
|
||||
|
||||
279
frontend/src/views/content/permissions.js
Normal file
279
frontend/src/views/content/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
279
frontend/src/views/permissions.js
Normal file
279
frontend/src/views/permissions.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is proprietary and confidential.
|
||||
* Unauthorized copying, modification, or distribution is prohibited.
|
||||
*
|
||||
* For licensing inquiries: info@hb3-accelerator.com
|
||||
* Website: https://hb3-accelerator.com
|
||||
* GitHub: https://github.com/HB3-ACCELERATOR
|
||||
*/
|
||||
|
||||
/**
|
||||
* Единая матрица прав доступа для DLE
|
||||
* Используется и на backend, и на frontend
|
||||
*/
|
||||
|
||||
// Роли в системе
|
||||
const ROLES = {
|
||||
GUEST: 'guest', // Неавторизованный гость
|
||||
USER: 'user', // Авторизованный гость (0 токенов)
|
||||
READONLY: 'readonly', // Админ чтение (токены > 0 && < X)
|
||||
EDITOR: 'editor' // Админ редактор (токены >= X)
|
||||
};
|
||||
|
||||
// Список всех прав в системе
|
||||
const PERMISSIONS = {
|
||||
// Публичный доступ
|
||||
VIEW_HOME: 'view_home',
|
||||
CHAT_AI: 'chat_ai',
|
||||
|
||||
// Получение сообщений
|
||||
RECEIVE_MESSAGES: 'receive_messages',
|
||||
|
||||
// Просмотр данных
|
||||
VIEW_CRM: 'view_crm',
|
||||
VIEW_CONTACTS: 'view_contacts',
|
||||
VIEW_DATA: 'view_data',
|
||||
|
||||
// Отправка сообщений
|
||||
SEND_TO_USERS: 'send_to_users',
|
||||
CHAT_WITH_ADMINS: 'chat_with_admins',
|
||||
|
||||
// AI функции
|
||||
GENERATE_AI_REPLIES: 'generate_ai_replies',
|
||||
|
||||
// Редактирование
|
||||
EDIT_USER_DATA: 'edit_user_data',
|
||||
EDIT_CONTACTS: 'edit_contacts',
|
||||
|
||||
// Удаление
|
||||
DELETE_USER_DATA: 'delete_user_data',
|
||||
DELETE_MESSAGES: 'delete_messages',
|
||||
|
||||
// Массовые операции
|
||||
BROADCAST: 'broadcast',
|
||||
|
||||
// Управление тегами
|
||||
MANAGE_TAGS: 'manage_tags',
|
||||
|
||||
// Блокировка пользователей
|
||||
BLOCK_USERS: 'block_users',
|
||||
|
||||
// Управление настройками
|
||||
MANAGE_SETTINGS: 'manage_settings',
|
||||
|
||||
// Контент: юридические документы
|
||||
VIEW_BASIC_DOCS: 'view_basic_docs', // Базовые документы для пользователей
|
||||
VIEW_LEGAL_DOCS: 'view_legal_docs', // Юридические документы для читателей
|
||||
MANAGE_LEGAL_DOCS: 'manage_legal_docs' // Управление документами для редакторов
|
||||
};
|
||||
|
||||
// Матрица: какая роль имеет какие права
|
||||
const PERMISSIONS_MAP = {
|
||||
[ROLES.GUEST]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI
|
||||
],
|
||||
|
||||
[ROLES.USER]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CONTACTS, // Пользователи могут видеть контакты для выбора
|
||||
PERMISSIONS.SEND_TO_USERS, // Пользователи могут отправлять сообщения
|
||||
PERMISSIONS.CHAT_WITH_ADMINS, // Авторизованные пользователи могут видеть личные сообщения
|
||||
PERMISSIONS.VIEW_BASIC_DOCS // Базовые документы для пользователей
|
||||
],
|
||||
|
||||
[ROLES.READONLY]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Чтение внутренних юридических документов
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS
|
||||
],
|
||||
|
||||
[ROLES.EDITOR]: [
|
||||
PERMISSIONS.VIEW_HOME,
|
||||
PERMISSIONS.CHAT_AI,
|
||||
PERMISSIONS.RECEIVE_MESSAGES,
|
||||
PERMISSIONS.VIEW_CRM,
|
||||
PERMISSIONS.VIEW_CONTACTS,
|
||||
PERMISSIONS.VIEW_DATA,
|
||||
PERMISSIONS.SEND_TO_USERS,
|
||||
PERMISSIONS.CHAT_WITH_ADMINS,
|
||||
PERMISSIONS.GENERATE_AI_REPLIES,
|
||||
PERMISSIONS.EDIT_USER_DATA,
|
||||
PERMISSIONS.EDIT_CONTACTS,
|
||||
PERMISSIONS.DELETE_USER_DATA,
|
||||
PERMISSIONS.DELETE_MESSAGES,
|
||||
PERMISSIONS.BROADCAST,
|
||||
PERMISSIONS.MANAGE_TAGS,
|
||||
PERMISSIONS.BLOCK_USERS,
|
||||
PERMISSIONS.MANAGE_SETTINGS,
|
||||
// Базовые документы для пользователей
|
||||
PERMISSIONS.VIEW_BASIC_DOCS,
|
||||
// Полный доступ к юридическим документам
|
||||
PERMISSIONS.VIEW_LEGAL_DOCS,
|
||||
PERMISSIONS.MANAGE_LEGAL_DOCS
|
||||
]
|
||||
};
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль определенное право
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {string} permission - Требуемое право
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasPermission(role, permission) {
|
||||
if (!role || !permission) return false;
|
||||
return PERMISSIONS_MAP[role]?.includes(permission) || false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все права для роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
function getPermissionsForRole(role) {
|
||||
return PERMISSIONS_MAP[role] || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ХОТЯ БЫ ОДНО из прав
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAnyPermission(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.some(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверяет, имеет ли роль ВСЕ указанные права
|
||||
* @param {string} role - Роль пользователя
|
||||
* @param {Array<string>} permissions - Список прав
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function hasAllPermissions(role, permissions) {
|
||||
if (!Array.isArray(permissions)) return false;
|
||||
return permissions.every(p => hasPermission(role, p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает описание роли
|
||||
* @param {string} role - Роль пользователя
|
||||
* @returns {string}
|
||||
*/
|
||||
function getRoleDescription(role) {
|
||||
const descriptions = {
|
||||
[ROLES.GUEST]: 'Неавторизованный гость',
|
||||
[ROLES.USER]: 'Авторизованный гость',
|
||||
[ROLES.READONLY]: 'Админ (только чтение)',
|
||||
[ROLES.EDITOR]: 'Админ (редактор)'
|
||||
};
|
||||
|
||||
return descriptions[role] || 'Неизвестная роль';
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить, может ли отправитель отправлять сообщения получателю
|
||||
* @param {string} senderRole - Роль отправителя
|
||||
* @param {string} recipientRole - Роль получателя
|
||||
* @param {number} senderId - ID отправителя
|
||||
* @param {number} recipientId - ID получателя
|
||||
* @returns {Object} { canSend: boolean, errorMessage?: string }
|
||||
*/
|
||||
function canSendMessage(senderRole, recipientRole, senderId, recipientId) {
|
||||
// Проверяем базовое право на отправку сообщений
|
||||
if (!hasPermission(senderRole, PERMISSIONS.SEND_TO_USERS)) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'У вас нет права на отправку сообщений'
|
||||
};
|
||||
}
|
||||
|
||||
// Собственный чат - всегда разрешен (для ИИ ассистента)
|
||||
if (senderId === recipientId) {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY могут писать только EDITOR
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') && recipientRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// EDITOR может писать всем (USER, READONLY, EDITOR)
|
||||
if (senderRole === 'editor') {
|
||||
return { canSend: true };
|
||||
}
|
||||
|
||||
// USER и READONLY НЕ могут писать друг другу
|
||||
if ((senderRole === 'user' || senderRole === 'readonly') &&
|
||||
(recipientRole === 'user' || recipientRole === 'readonly')) {
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: 'Пользователи и читатели не могут отправлять сообщения друг другу'
|
||||
};
|
||||
}
|
||||
|
||||
// Остальные случаи запрещены
|
||||
return {
|
||||
canSend: false,
|
||||
errorMessage: `Роль ${senderRole} не может отправлять сообщения роли ${recipientRole}`
|
||||
};
|
||||
}
|
||||
|
||||
// Экспорты для CommonJS (Node.js)
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
// ES модули для Frontend
|
||||
export {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
|
||||
// CommonJS для Backend
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
ROLES,
|
||||
PERMISSIONS,
|
||||
PERMISSIONS_MAP,
|
||||
hasPermission,
|
||||
getPermissionsForRole,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
getRoleDescription,
|
||||
canSendMessage
|
||||
};
|
||||
}
|
||||
|
||||
0
scripts/ssh-key-server.js
Executable file → Normal file
0
scripts/ssh-key-server.js
Executable file → Normal file
@@ -22,8 +22,7 @@ README*
|
||||
.git/
|
||||
.gitignore
|
||||
|
||||
# Зависимости (будут установлены в контейнере)
|
||||
node_modules/
|
||||
# Логи установки
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
Reference in New Issue
Block a user