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
|
- **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
|
```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
|
```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/
|
.git/
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
||||||
# Зависимости (будут установлены в контейнере)
|
# Логи установки
|
||||||
node_modules/
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ const cors = require('cors');
|
|||||||
const session = require('express-session');
|
const session = require('express-session');
|
||||||
const sessionConfig = require('./config/session');
|
const sessionConfig = require('./config/session');
|
||||||
const logger = require('./utils/logger');
|
const logger = require('./utils/logger');
|
||||||
|
const rateLimit = require('express-rate-limit');
|
||||||
// const csurf = require('csurf'); // Закомментировано, так как не используется
|
// const csurf = require('csurf'); // Закомментировано, так как не используется
|
||||||
const errorHandler = require('./middleware/errorHandler');
|
const errorHandler = require('./middleware/errorHandler');
|
||||||
// const { version } = require('./package.json'); // Закомментировано, так как не используется
|
// const { version } = require('./package.json'); // Закомментировано, так как не используется
|
||||||
@@ -115,14 +116,21 @@ app.set('host', '0.0.0.0');
|
|||||||
app.set('port', process.env.PORT || 8000);
|
app.set('port', process.env.PORT || 8000);
|
||||||
|
|
||||||
// Настройка CORS
|
// Настройка 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(
|
app.use(
|
||||||
cors({
|
cors({
|
||||||
origin: [
|
origin: corsOrigins,
|
||||||
'http://localhost:5173',
|
|
||||||
'http://127.0.0.1:5173',
|
|
||||||
'https://hb3-accelerator.com',
|
|
||||||
'https://www.hb3-accelerator.com',
|
|
||||||
],
|
|
||||||
credentials: true,
|
credentials: true,
|
||||||
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
|
||||||
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'],
|
allowedHeaders: ['Content-Type', 'Authorization', 'Cookie'],
|
||||||
@@ -171,6 +179,36 @@ app.use((req, res, next) => {
|
|||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: true }));
|
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)
|
// Статическая раздача загруженных файлов (для dev и prod)
|
||||||
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));
|
||||||
app.use('/api/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(
|
app.use(
|
||||||
helmet({
|
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
|
// Маршруты API
|
||||||
app.use('/api/tables', tablesRoutes); // ДОЛЖНО БЫТЬ ВЫШЕ!
|
app.use('/api/tables', tablesRoutes); // ДОЛЖНО БЫТЬ ВЫШЕ!
|
||||||
// app.use('/api', identitiesRoutes);
|
// 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/users', usersRoutes);
|
||||||
app.use('/api/chat', chatRoutes);
|
app.use('/api/chat', chatRoutes);
|
||||||
app.use('/api/admin', adminRoutes);
|
app.use('/api/admin', adminRoutes);
|
||||||
@@ -195,10 +245,10 @@ app.use('/api/kpp', kppRoutes); // Добавленное использован
|
|||||||
app.use('/api/geocoding', geocodingRoutes); // Добавленное использование роута
|
app.use('/api/geocoding', geocodingRoutes); // Добавленное использование роута
|
||||||
|
|
||||||
app.use('/api/dle-v2', dleV2Routes); // Добавляем маршрут DLE v2
|
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/countries', countriesRoutes); // Добавляем маршрут стран
|
||||||
app.use('/api/russian-classifiers', russianClassifiersRoutes); // Добавляем маршрут российских классификаторов
|
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/ai-queue', aiQueueRoutes); // Добавляем маршрут AI Queue
|
||||||
app.use('/api/tags', tagsRoutes); // Добавляем маршрут тегов
|
app.use('/api/tags', tagsRoutes); // Добавляем маршрут тегов
|
||||||
app.use('/api/blockchain', blockchainRoutes); // Добавляем маршрут blockchain
|
app.use('/api/blockchain', blockchainRoutes); // Добавляем маршрут blockchain
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ function setPoolChangeCallback(cb) {
|
|||||||
let sessionMiddleware = createSessionMiddleware();
|
let sessionMiddleware = createSessionMiddleware();
|
||||||
|
|
||||||
function createSessionMiddleware() {
|
function createSessionMiddleware() {
|
||||||
|
const isProduction = process.env.NODE_ENV === 'production';
|
||||||
|
|
||||||
return session({
|
return session({
|
||||||
store: new pgSession({
|
store: new pgSession({
|
||||||
pool: db.getPool(),
|
pool: db.getPool(),
|
||||||
@@ -36,8 +38,8 @@ function createSessionMiddleware() {
|
|||||||
cookie: {
|
cookie: {
|
||||||
maxAge: 30 * 24 * 60 * 60 * 1000,
|
maxAge: 30 * 24 * 60 * 60 * 1000,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
secure: false,
|
secure: false, // false для локального Docker (HTTP)
|
||||||
sameSite: 'lax',
|
sameSite: 'lax', // lax для локального Docker
|
||||||
path: '/',
|
path: '/',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -787,21 +787,25 @@ router.get('/encryption-key/status', requireAdmin, async (req, res) => {
|
|||||||
|
|
||||||
const exists = fs.existsSync(keyPath);
|
const exists = fs.existsSync(keyPath);
|
||||||
|
|
||||||
let key = null;
|
// Возвращаем только метаданные без содержимого ключа
|
||||||
if (exists) {
|
let checksum = null;
|
||||||
try {
|
if (exists) {
|
||||||
key = fs.readFileSync(keyPath, 'utf8').trim();
|
try {
|
||||||
} catch (error) {
|
const data = fs.readFileSync(keyPath);
|
||||||
logger.error('Ошибка чтения ключа:', error);
|
// лёгкая хэш-сумма для проверки целостности без раскрытия ключа
|
||||||
}
|
const crypto = require('crypto');
|
||||||
|
checksum = crypto.createHash('sha256').update(data).digest('hex');
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Ошибка чтения ключа для метаданных:', error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
res.json({
|
|
||||||
success: true,
|
res.json({
|
||||||
exists,
|
success: true,
|
||||||
path: keyPath,
|
exists,
|
||||||
key: key
|
path: keyPath,
|
||||||
});
|
checksum
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Ошибка проверки статуса ключа шифрования:', error);
|
logger.error('Ошибка проверки статуса ключа шифрования:', error);
|
||||||
res.status(500).json({ success: false, error: error.message });
|
res.status(500).json({ success: false, error: error.message });
|
||||||
|
|||||||
@@ -1,48 +1,10 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const https = require('https');
|
|
||||||
const { promisify } = require('util');
|
const { promisify } = require('util');
|
||||||
const dns = require('dns');
|
const dns = require('dns');
|
||||||
|
|
||||||
const resolve4 = promisify(dns.resolve4);
|
const resolve4 = promisify(dns.resolve4);
|
||||||
|
|
||||||
const SSH_DIR = path.join(process.env.HOME || process.env.USERPROFILE, '.ssh');
|
// Удалено: эндпоинты выдачи приватного/публичного 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' });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// GET /api/dns-check/:domain - Check DNS and get IP address
|
// GET /api/dns-check/:domain - Check DNS and get IP address
|
||||||
router.get('/dns-check/:domain', async (req, res) => {
|
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_DB=${DB_NAME:-dapp_db}
|
||||||
- POSTGRES_USER=${DB_USER:-dapp_user}
|
- POSTGRES_USER=${DB_USER:-dapp_user}
|
||||||
- POSTGRES_PASSWORD=${DB_PASSWORD:-dapp_password}
|
- POSTGRES_PASSWORD=${DB_PASSWORD:-dapp_password}
|
||||||
ports:
|
|
||||||
- '5432:5432' # Открываем доступ к базе данных извне для разработки
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test:
|
test:
|
||||||
- CMD-SHELL
|
- CMD-SHELL
|
||||||
@@ -138,7 +136,7 @@ services:
|
|||||||
- ./ssl:/app/ssl
|
- ./ssl:/app/ssl
|
||||||
- ./shared:/app/shared:ro
|
- ./shared:/app/shared:ro
|
||||||
environment:
|
environment:
|
||||||
- NODE_ENV=${NODE_ENV:-development}
|
- NODE_ENV=${NODE_ENV:-production}
|
||||||
- PORT=${PORT:-8000}
|
- PORT=${PORT:-8000}
|
||||||
- DB_HOST=postgres
|
- DB_HOST=postgres
|
||||||
- DB_PORT=5432
|
- DB_PORT=5432
|
||||||
@@ -150,11 +148,12 @@ services:
|
|||||||
- OLLAMA_BASE_URL=http://ollama:11434
|
- OLLAMA_BASE_URL=http://ollama:11434
|
||||||
- OLLAMA_MODEL=${OLLAMA_MODEL:-qwen2.5:7b}
|
- OLLAMA_MODEL=${OLLAMA_MODEL:-qwen2.5:7b}
|
||||||
- OLLAMA_EMBEDDINGS_MODEL=${OLLAMA_EMBEDDINGS_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
|
- VECTOR_SEARCH_URL=http://vector-search:8001
|
||||||
# Factory адреса теперь хранятся в базе данных
|
# Factory адреса теперь хранятся в базе данных
|
||||||
ports:
|
# Убираем порты для продакшна - доступ только через nginx
|
||||||
- '8000:8000'
|
# ports:
|
||||||
|
# - '8000:8000'
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
- host.docker.internal:host-gateway
|
- host.docker.internal:host-gateway
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -164,6 +163,7 @@ services:
|
|||||||
retries: 5
|
retries: 5
|
||||||
start_period: 60s
|
start_period: 60s
|
||||||
frontend:
|
frontend:
|
||||||
|
profiles: ["dev"] # Только для разработки
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
@@ -204,37 +204,33 @@ services:
|
|||||||
- "9000:80" # Frontend nginx (для production на VDS)
|
- "9000:80" # Frontend nginx (для production на VDS)
|
||||||
- "9443:443" # HTTPS порт для production на VDS
|
- "9443:443" # HTTPS порт для production на VDS
|
||||||
environment:
|
environment:
|
||||||
- DOMAIN=${DOMAIN:-localhost:9000}
|
- DOMAIN=${DOMAIN:-production.local}
|
||||||
- BACKEND_CONTAINER=dapp-backend
|
- BACKEND_CONTAINER=dapp-backend
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# SSH Key Server для безопасной передачи ключей
|
# SSH Key Server отключен по безопасности (оставлен пример профиля dev при необходимости)
|
||||||
ssh-key-server:
|
# ssh-key-server:
|
||||||
image: node:20-slim
|
# profiles: ["dev"]
|
||||||
container_name: dapp-ssh-key-server
|
# image: node:20-slim
|
||||||
restart: unless-stopped
|
# container_name: dapp-ssh-key-server
|
||||||
dns:
|
# restart: unless-stopped
|
||||||
- 1.1.1.1 # Cloudflare (приватность)
|
# dns:
|
||||||
- 9.9.9.9 # Quad9 (безопасность + блокировка вредоносных доменов)
|
# - 1.1.1.1
|
||||||
- 8.8.8.8 # Google (надежность, fallback)
|
# - 9.9.9.9
|
||||||
volumes:
|
# - 8.8.8.8
|
||||||
- ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
|
# volumes:
|
||||||
- ./ssl:/app/ssl
|
# - ./scripts/ssh-key-server.js:/app/ssh-key-server.js:ro
|
||||||
- ~/.ssh:/root/.ssh:rw
|
# - ./ssl:/app/ssl:ro
|
||||||
ports:
|
# - ~/.ssh:/root/.ssh:ro
|
||||||
- '3001:3001'
|
# command: node /app/ssh-key-server.js
|
||||||
command: node /app/ssh-key-server.js
|
# # Порт намеренно не публикуется, без healthcheck
|
||||||
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
|
|
||||||
|
|
||||||
# WebSSH Agent для настройки VDS
|
# WebSSH Agent для настройки VDS
|
||||||
webssh-agent:
|
webssh-agent:
|
||||||
|
profiles: ["dev"] # Только для разработки
|
||||||
build:
|
build:
|
||||||
context: ./webssh-agent
|
context: ./webssh-agent
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ README*
|
|||||||
.git/
|
.git/
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
||||||
# Зависимости (будут установлены в контейнере)
|
# Логи установки
|
||||||
node_modules/
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ echo " DOMAIN: $DOMAIN"
|
|||||||
echo " BACKEND_CONTAINER: $BACKEND_CONTAINER"
|
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)"
|
echo " Режим: ЛОКАЛЬНАЯ РАЗРАБОТКА (без SSL)"
|
||||||
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
|
TEMPLATE_FILE="/etc/nginx/nginx-local.conf.template"
|
||||||
else
|
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 { useContactsAndMessagesWebSocket } from '../composables/useContactsWebSocket';
|
||||||
import { usePermissions } from '@/composables/usePermissions';
|
import { usePermissions } from '@/composables/usePermissions';
|
||||||
import { useAuthContext } from '@/composables/useAuth';
|
import { useAuthContext } from '@/composables/useAuth';
|
||||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
import { PERMISSIONS } from './permissions.js';
|
||||||
import api from '../api/axios';
|
import api from '../api/axios';
|
||||||
import { sendMessage, getPrivateUnreadCount } from '../services/messagesService';
|
import { sendMessage, getPrivateUnreadCount } from '../services/messagesService';
|
||||||
import { useRoles } from '@/composables/useRoles';
|
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 { computed } from 'vue';
|
||||||
import { useAuthContext } from './useAuth';
|
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 для работы с правами доступа
|
* Composable для работы с правами доступа
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const SettingsInterfaceView = () => import('../views/settings/Interface/Interfac
|
|||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { setToStorage } from '../utils/storage.js';
|
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');
|
// 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 { useRouter, useRoute } from 'vue-router';
|
||||||
import BaseLayout from '../components/BaseLayout.vue';
|
import BaseLayout from '../components/BaseLayout.vue';
|
||||||
import pagesService from '../services/pagesService';
|
import pagesService from '../services/pagesService';
|
||||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
import { PERMISSIONS } from './permissions.js';
|
||||||
import { useAuthContext } from '../composables/useAuth';
|
import { useAuthContext } from '../composables/useAuth';
|
||||||
import { usePermissions } from '../composables/usePermissions';
|
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 { getPublicMessages, getConversationByUserId, sendMessage, getPersonalChatHistory } from '../../services/messagesService.js';
|
||||||
import { useAuthContext } from '@/composables/useAuth';
|
import { useAuthContext } from '@/composables/useAuth';
|
||||||
import { usePermissions } from '@/composables/usePermissions';
|
import { usePermissions } from '@/composables/usePermissions';
|
||||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
import { PERMISSIONS } from './permissions.js';
|
||||||
import { useContactsAndMessagesWebSocket } from '@/composables/useContactsWebSocket';
|
import { useContactsAndMessagesWebSocket } from '@/composables/useContactsWebSocket';
|
||||||
const { canEditContacts, canDeleteData, canManageTags, canBlockUsers, canSendToUsers, canGenerateAI, canViewContacts, hasPermission } = usePermissions();
|
const { canEditContacts, canDeleteData, canManageTags, canBlockUsers, canSendToUsers, canGenerateAI, canViewContacts, hasPermission } = usePermissions();
|
||||||
const { address, userId: currentUserId } = useAuthContext();
|
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 pagesService from '../../services/pagesService';
|
||||||
import { useAuthContext } from '../../composables/useAuth';
|
import { useAuthContext } from '../../composables/useAuth';
|
||||||
import { usePermissions } from '../../composables/usePermissions';
|
import { usePermissions } from '../../composables/usePermissions';
|
||||||
import { PERMISSIONS } from '/app/shared/permissions.js';
|
import { PERMISSIONS } from './permissions.js';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
isAuthenticated: { type: Boolean, default: false },
|
isAuthenticated: { type: Boolean, default: false },
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ import pagesService from '../../services/pagesService';
|
|||||||
import api from '../../api/axios';
|
import api from '../../api/axios';
|
||||||
import { useAuthContext } from '../../composables/useAuth';
|
import { useAuthContext } from '../../composables/useAuth';
|
||||||
import { usePermissions } from '../../composables/usePermissions';
|
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({
|
const props = defineProps({
|
||||||
isAuthenticated: { type: Boolean, default: false },
|
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/
|
.git/
|
||||||
.gitignore
|
.gitignore
|
||||||
|
|
||||||
# Зависимости (будут установлены в контейнере)
|
# Логи установки
|
||||||
node_modules/
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
|||||||
Reference in New Issue
Block a user