ваше сообщение коммита
This commit is contained in:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -202,4 +202,14 @@ backend/test_*.js
|
||||
|
||||
# Environment specific files
|
||||
backend/.env.local
|
||||
backend/.env.production
|
||||
backend/.env.production
|
||||
|
||||
# Server management scripts - may contain sensitive information
|
||||
scripts/clean-server.sh
|
||||
scripts/export-template-for-release.sh
|
||||
|
||||
# Docker data and release archives - не коммитить в Git!
|
||||
docker-data/
|
||||
dle-template.tar.gz
|
||||
dle-template.tar.gz.part-*
|
||||
dle-template.tar.gz.join.sh
|
||||
@@ -36,7 +36,8 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup.s
|
||||
The script automatically downloads the latest artifacts from the release and deploys `docker-data`.
|
||||
|
||||
### 📦 Releases and artifacts
|
||||
- [Release v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — contains an archive split into parts (`dle-template.tar.gz.part-*`) that is installed together with the script.
|
||||
- [Release v1.0.1](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.1) (Latest) — contains the complete application template with Docker images, volumes, and encryption key. Archive is split into parts (`dle-template.tar.gz.part-*`) for easy download.
|
||||
- [Release v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — previous version.
|
||||
|
||||
### Running the application
|
||||
```bash
|
||||
|
||||
@@ -36,7 +36,8 @@ curl -fsSL https://raw.githubusercontent.com/VC-HB3-Accelerator/DLE/main/setup.s
|
||||
Скрипт автоматически скачивает последние артефакты из релиза и разворачивает `docker-data`.
|
||||
|
||||
### 📦 Релизы и артефакты
|
||||
- [Релиз v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — содержит архив, разбитый на части (`dle-template.tar.gz.part-*`), который устанавливается вместе со скриптом.
|
||||
- [Релиз v1.0.1](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.1) (Latest) — содержит полный шаблон приложения с Docker образами, томами и ключом шифрования. Архив разделен на части (`dle-template.tar.gz.part-*`) для удобства загрузки.
|
||||
- [Релиз v1.0.0](https://github.com/VC-HB3-Accelerator/DLE/releases/tag/v1.0.0) — предыдущая версия.
|
||||
|
||||
### Запуск приложения
|
||||
```bash
|
||||
|
||||
@@ -88,6 +88,24 @@ router.get('/okved', async (req, res, next) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Сортировка кодов ОКВЭД по коду (правильная числовая сортировка для каждой части)
|
||||
codes.sort((a, b) => {
|
||||
// Разбиваем коды на части для правильной сортировки
|
||||
const partsA = a.code.split('.').map(p => parseInt(p, 10));
|
||||
const partsB = b.code.split('.').map(p => parseInt(p, 10));
|
||||
|
||||
// Сравниваем части по порядку численно
|
||||
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
||||
const partA = partsA[i] !== undefined ? partsA[i] : 0;
|
||||
const partB = partsB[i] !== undefined ? partsB[i] : 0;
|
||||
|
||||
if (partA !== partB) {
|
||||
return partA - partB;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// Ограничиваем количество результатов для производительности
|
||||
const limit = parseInt(req.query.limit) || 2000; // Увеличили лимит для полного списка
|
||||
codes = codes.slice(0, limit);
|
||||
|
||||
@@ -91,7 +91,7 @@ async function runMigrations() {
|
||||
}
|
||||
|
||||
// Извлекаем только UP SQL
|
||||
const sqlToExecute = fileContent.substring(upSqlStartIndex, upSqlEndIndex).trim();
|
||||
let sqlToExecute = fileContent.substring(upSqlStartIndex, upSqlEndIndex).trim();
|
||||
|
||||
if (!sqlToExecute) {
|
||||
logger.warn(`Migration file ${file} has no executable UP SQL content. Skipping.`);
|
||||
@@ -99,6 +99,38 @@ async function runMigrations() {
|
||||
}
|
||||
|
||||
logger.info(`Executing UP migration from ${file}...`);
|
||||
|
||||
// Выделяем CREATE EXTENSION команды, которые должны выполняться вне транзакции
|
||||
const extensionRegex = /CREATE\s+EXTENSION\s+IF\s+NOT\s+EXISTS\s+\w+;?/gi;
|
||||
const extensionCommands = [];
|
||||
sqlToExecute = sqlToExecute.replace(extensionRegex, (match) => {
|
||||
extensionCommands.push(match.replace(/;?\s*$/, ''));
|
||||
return ''; // Удаляем из основного SQL
|
||||
});
|
||||
|
||||
// Выполняем CREATE EXTENSION команды вне транзакции
|
||||
for (const extCmd of extensionCommands) {
|
||||
try {
|
||||
await pool.query(extCmd);
|
||||
logger.info(`Extension command executed: ${extCmd}`);
|
||||
} catch (error) {
|
||||
// Игнорируем ошибку, если расширение уже установлено
|
||||
if (!error.message.includes('already exists')) {
|
||||
logger.warn(`Warning executing extension command: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Очищаем оставшийся SQL от пустых строк
|
||||
sqlToExecute = sqlToExecute.trim();
|
||||
|
||||
// Если после удаления CREATE EXTENSION остался только пустой SQL, пропускаем транзакцию
|
||||
if (!sqlToExecute) {
|
||||
await pool.query('INSERT INTO migrations (name) VALUES ($1)', [file]);
|
||||
logger.info(`Migration ${file} executed successfully (extension only)`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await pool.query('BEGIN');
|
||||
try {
|
||||
// Создаем функцию для получения ключа шифрования
|
||||
|
||||
@@ -1320,6 +1320,24 @@ const fetchOkvedCodes = async (level, parentCode, optionsRef, loadingRef) => {
|
||||
);
|
||||
}
|
||||
|
||||
// Сортировка кодов ОКВЭД по коду (правильная числовая сортировка для каждой части)
|
||||
filteredCodes.sort((a, b) => {
|
||||
// Разбиваем коды на части для правильной сортировки
|
||||
const partsA = a.code.split('.').map(p => parseInt(p, 10));
|
||||
const partsB = b.code.split('.').map(p => parseInt(p, 10));
|
||||
|
||||
// Сравниваем части по порядку численно
|
||||
for (let i = 0; i < Math.max(partsA.length, partsB.length); i++) {
|
||||
const partA = partsA[i] !== undefined ? partsA[i] : 0;
|
||||
const partB = partsB[i] !== undefined ? partsB[i] : 0;
|
||||
|
||||
if (partA !== partB) {
|
||||
return partA - partB;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
optionsRef.value = filteredCodes.map(code => ({
|
||||
value: code.code,
|
||||
text: `${code.code} - ${code.title}`
|
||||
|
||||
@@ -23,12 +23,34 @@ fi
|
||||
ENCRYPTION_KEY=$(cat ./ssl/keys/full_db_encryption.key)
|
||||
|
||||
# Создаем роли Read-Only и Editor
|
||||
# Используем DO блок для безопасной вставки с проверкой уникальности name_encrypted
|
||||
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
|
||||
INSERT INTO roles (id, name_encrypted) VALUES
|
||||
(1, encrypt_text('readonly', '$ENCRYPTION_KEY')),
|
||||
(2, encrypt_text('editor', '$ENCRYPTION_KEY'))
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
name_encrypted = EXCLUDED.name_encrypted;"
|
||||
DO \$\$
|
||||
DECLARE
|
||||
readonly_id INTEGER;
|
||||
editor_id INTEGER;
|
||||
BEGIN
|
||||
-- Проверяем и создаем/обновляем роль readonly
|
||||
SELECT id INTO readonly_id FROM roles WHERE decrypt_text(name_encrypted, get_encryption_key()) = 'readonly' LIMIT 1;
|
||||
IF readonly_id IS NULL THEN
|
||||
-- Если роли нет, пытаемся вставить с id=1, если занято - используем следующий доступный
|
||||
BEGIN
|
||||
INSERT INTO roles (id, name_encrypted) VALUES (1, encrypt_text('readonly', get_encryption_key()));
|
||||
EXCEPTION WHEN unique_violation THEN
|
||||
INSERT INTO roles (name_encrypted) VALUES (encrypt_text('readonly', get_encryption_key()));
|
||||
END;
|
||||
END IF;
|
||||
|
||||
-- Проверяем и создаем/обновляем роль editor
|
||||
SELECT id INTO editor_id FROM roles WHERE decrypt_text(name_encrypted, get_encryption_key()) = 'editor' LIMIT 1;
|
||||
IF editor_id IS NULL THEN
|
||||
BEGIN
|
||||
INSERT INTO roles (id, name_encrypted) VALUES (2, encrypt_text('editor', get_encryption_key()));
|
||||
EXCEPTION WHEN unique_violation THEN
|
||||
INSERT INTO roles (name_encrypted) VALUES (encrypt_text('editor', get_encryption_key()));
|
||||
END;
|
||||
END IF;
|
||||
END \$\$;"
|
||||
|
||||
# Заполняем справочную таблицу is_rag_source
|
||||
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
|
||||
@@ -38,17 +60,87 @@ INSERT INTO is_rag_source (id, name_encrypted) VALUES
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
name_encrypted = EXCLUDED.name_encrypted;"
|
||||
|
||||
# Заполняем RPC провайдеры с проверкой дубликатов
|
||||
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
|
||||
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
|
||||
VALUES
|
||||
(encrypt_text('sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://1rpc.io/sepolia', '$ENCRYPTION_KEY'), 11155111),
|
||||
(encrypt_text('arbitrum-sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://sepolia-rollup.arbitrum.io/rpc', '$ENCRYPTION_KEY'), 421614),
|
||||
(encrypt_text('base-sepolia', '$ENCRYPTION_KEY'), encrypt_text('https://sepolia.base.org', '$ENCRYPTION_KEY'), 84532)
|
||||
ON CONFLICT DO NOTHING;"
|
||||
DO \$\$
|
||||
BEGIN
|
||||
-- Sepolia
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM rpc_providers
|
||||
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'sepolia'
|
||||
AND chain_id = 11155111
|
||||
) THEN
|
||||
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
|
||||
VALUES (encrypt_text('sepolia', get_encryption_key()), encrypt_text('https://1rpc.io/sepolia', get_encryption_key()), 11155111);
|
||||
END IF;
|
||||
|
||||
-- Arbitrum Sepolia
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM rpc_providers
|
||||
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'arbitrum-sepolia'
|
||||
AND chain_id = 421614
|
||||
) THEN
|
||||
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
|
||||
VALUES (encrypt_text('arbitrum-sepolia', get_encryption_key()), encrypt_text('https://sepolia-rollup.arbitrum.io/rpc', get_encryption_key()), 421614);
|
||||
END IF;
|
||||
|
||||
-- Base Sepolia
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM rpc_providers
|
||||
WHERE decrypt_text(network_id_encrypted, get_encryption_key()) = 'base-sepolia'
|
||||
AND chain_id = 84532
|
||||
) THEN
|
||||
INSERT INTO rpc_providers (network_id_encrypted, rpc_url_encrypted, chain_id)
|
||||
VALUES (encrypt_text('base-sepolia', get_encryption_key()), encrypt_text('https://sepolia.base.org', get_encryption_key()), 84532);
|
||||
END IF;
|
||||
END \$\$;"
|
||||
|
||||
# Заполняем токены аутентификации с проверкой дубликатов
|
||||
docker exec dapp-postgres psql -U dapp_user -d dapp_db -c "
|
||||
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
|
||||
VALUES
|
||||
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1),
|
||||
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('arbitrum-sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1),
|
||||
(encrypt_text('DLE', '$ENCRYPTION_KEY'), encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', '$ENCRYPTION_KEY'), encrypt_text('base-sepolia', '$ENCRYPTION_KEY'), 1.000000000000000000, 1, 1)
|
||||
ON CONFLICT DO NOTHING;"
|
||||
DO \$\$
|
||||
BEGIN
|
||||
-- Sepolia token
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM auth_tokens
|
||||
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'sepolia'
|
||||
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
|
||||
) THEN
|
||||
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
|
||||
VALUES (
|
||||
encrypt_text('DLE', get_encryption_key()),
|
||||
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
|
||||
encrypt_text('sepolia', get_encryption_key()),
|
||||
1.000000000000000000, 1, 1
|
||||
);
|
||||
END IF;
|
||||
|
||||
-- Arbitrum Sepolia token
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM auth_tokens
|
||||
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'arbitrum-sepolia'
|
||||
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
|
||||
) THEN
|
||||
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
|
||||
VALUES (
|
||||
encrypt_text('DLE', get_encryption_key()),
|
||||
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
|
||||
encrypt_text('arbitrum-sepolia', get_encryption_key()),
|
||||
1.000000000000000000, 1, 1
|
||||
);
|
||||
END IF;
|
||||
|
||||
-- Base Sepolia token
|
||||
IF NOT EXISTS (
|
||||
SELECT 1 FROM auth_tokens
|
||||
WHERE decrypt_text(network_encrypted, get_encryption_key()) = 'base-sepolia'
|
||||
AND decrypt_text(address_encrypted, get_encryption_key()) = '0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386'
|
||||
) THEN
|
||||
INSERT INTO auth_tokens (name_encrypted, address_encrypted, network_encrypted, min_balance, readonly_threshold, editor_threshold)
|
||||
VALUES (
|
||||
encrypt_text('DLE', get_encryption_key()),
|
||||
encrypt_text('0xdD27a91692da59d1Ee7dD1Fb342B9f1B5FF29386', get_encryption_key()),
|
||||
encrypt_text('base-sepolia', get_encryption_key()),
|
||||
1.000000000000000000, 1, 1
|
||||
);
|
||||
END IF;
|
||||
END \$\$;"
|
||||
|
||||
30
setup.sh
30
setup.sh
@@ -24,14 +24,13 @@ print_red() {
|
||||
echo -e "\e[31m$1\e[0m"
|
||||
}
|
||||
|
||||
ARCHIVE_VERSION="v1.0.0"
|
||||
ARCHIVE_VERSION="v1.0.1"
|
||||
ARCHIVE_BASE_URL="https://github.com/VC-HB3-Accelerator/DLE/releases/download/${ARCHIVE_VERSION}"
|
||||
ARCHIVE_PARTS=(
|
||||
"dle-template.tar.gz.part-aa"
|
||||
"dle-template.tar.gz.part-ab"
|
||||
"dle-template.tar.gz.part-ac"
|
||||
"dle-template.tar.gz.part-ad"
|
||||
"dle-template.tar.gz.part-ae"
|
||||
)
|
||||
|
||||
# Проверка curl
|
||||
@@ -263,6 +262,30 @@ import_volumes() {
|
||||
print_green "✅ Все тома импортированы"
|
||||
}
|
||||
|
||||
# Копирование ключа шифрования из архива
|
||||
copy_encryption_key() {
|
||||
print_blue "🔐 Копирование ключа шифрования..."
|
||||
|
||||
# Проверяем наличие ключа в архиве
|
||||
if [ -f "docker-data/ssl/keys/full_db_encryption.key" ]; then
|
||||
# Создаем директорию для ключа
|
||||
mkdir -p ssl/keys
|
||||
|
||||
# Копируем ключ
|
||||
cp docker-data/ssl/keys/full_db_encryption.key ssl/keys/full_db_encryption.key
|
||||
chmod 600 ssl/keys/full_db_encryption.key
|
||||
|
||||
print_green "✅ Ключ шифрования скопирован из архива"
|
||||
print_yellow "⚠️ Примечание: Это дефолтный ключ, замените его на свой!"
|
||||
else
|
||||
print_yellow "⚠️ Ключ шифрования не найден в архиве"
|
||||
print_blue "Создайте новый ключ или он будет создан автоматически"
|
||||
|
||||
# Создаем директорию для ключа на всякий случай
|
||||
mkdir -p ssl/keys
|
||||
fi
|
||||
}
|
||||
|
||||
# Запуск приложения
|
||||
start_application() {
|
||||
print_blue "🚀 Запуск приложения..."
|
||||
@@ -314,6 +337,9 @@ main() {
|
||||
create_volumes
|
||||
import_volumes
|
||||
|
||||
# Копирование ключа шифрования
|
||||
copy_encryption_key
|
||||
|
||||
# Запуск
|
||||
start_application
|
||||
check_status
|
||||
|
||||
Reference in New Issue
Block a user