feat: добавлена возможность импорта из wg-easy и 3x-ui панелей

Основные изменения:
- Создан класс PanelImporter для парсинга и импорта клиентов
- Добавлена поддержка wg-easy (db.json)
- Добавлена поддержка 3x-ui (export JSON)
- Создана таблица panel_imports для отслеживания истории
- Добавлен UI для загрузки backup файлов при создании сервера
- Добавлены API endpoints: POST /api/servers/{id}/import и GET /api/servers/{id}/imports
- Автоматический импорт после деплоя сервера
- Переводы на всех 6 языках (EN, RU, ES, DE, FR, ZH)
- Обновлена документация в README

Функционал:
- Импорт клиентов с сохранением ключей и IP (wg-easy)
- Импорт клиентов с автогенерацией ключей (3x-ui)
- Поддержка экспирации и лимитов трафика из исходных панелей
- История импортов с информацией о количестве клиентов
- Обработка ошибок с детальным логированием
This commit is contained in:
infosave2007
2025-11-08 12:40:43 +03:00
parent bbb0fbeeb9
commit fc39346240
12 changed files with 643 additions and 10 deletions
+136
View File
@@ -18,6 +18,7 @@ require_once __DIR__ . '/../inc/VpnServer.php';
require_once __DIR__ . '/../inc/VpnClient.php';
require_once __DIR__ . '/../inc/Translator.php';
require_once __DIR__ . '/../inc/JWT.php';
require_once __DIR__ . '/../inc/PanelImporter.php';
// Load environment configuration
Config::load(__DIR__ . '/../.env');
@@ -252,6 +253,21 @@ Router::post('/servers/create', function () {
'password' => $password,
]);
// Handle import if enabled
if (!empty($_POST['enable_import']) && !empty($_POST['panel_type']) && isset($_FILES['backup_file'])) {
$panelType = $_POST['panel_type'];
if (in_array($panelType, ['wg-easy', '3x-ui']) && $_FILES['backup_file']['error'] === UPLOAD_ERR_OK) {
// Store import info in session for processing after deployment
$_SESSION['pending_import'] = [
'server_id' => $serverId,
'panel_type' => $panelType,
'backup_file' => $_FILES['backup_file']['tmp_name'],
'backup_name' => $_FILES['backup_file']['name']
];
}
}
redirect('/servers/' . $serverId . '/deploy');
} catch (Exception $e) {
View::render('servers/create.twig', ['error' => $e->getMessage()]);
@@ -355,9 +371,48 @@ Router::get('/servers/{id}', function ($params) {
// Get clients for this server
$clients = VpnClient::listByServer($serverId);
// Check for pending import
$importMessage = null;
if (!empty($_SESSION['pending_import']) && $_SESSION['pending_import']['server_id'] == $serverId) {
$pendingImport = $_SESSION['pending_import'];
// Only process import if server is active
if ($serverData['status'] === 'active') {
try {
$backupContent = file_get_contents($pendingImport['backup_file']);
$importer = new PanelImporter($serverId, $user['id'], $pendingImport['panel_type']);
$importer->parseBackupFile($backupContent);
$result = $importer->import();
if ($result['success']) {
$importMessage = [
'type' => 'success',
'text' => "Successfully imported {$result['imported_count']} clients"
];
}
// Clean up
@unlink($pendingImport['backup_file']);
unset($_SESSION['pending_import']);
} catch (Exception $e) {
$importMessage = [
'type' => 'error',
'text' => 'Import failed: ' . $e->getMessage()
];
unset($_SESSION['pending_import']);
}
// Refresh clients list after import
$clients = VpnClient::listByServer($serverId);
}
}
View::render('servers/view.twig', [
'server' => $serverData,
'clients' => $clients,
'import_message' => $importMessage,
]);
} catch (Exception $e) {
error_log('Server view error: ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine());
@@ -802,6 +857,87 @@ Router::delete('/api/servers/{id}/delete', function ($params) {
header('Content-Type: application/json');
$user = JWT::requireAuth();
// API: Import from existing panel
Router::post('/api/servers/{id}/import', function ($params) {
header('Content-Type: application/json');
$user = JWT::requireAuth();
if (!$user) return;
$serverId = (int)$params['id'];
// Validate server ownership
$server = VpnServer::getById($serverId);
if (!$server || $server['user_id'] != $user['id']) {
http_response_code(404);
echo json_encode(['error' => 'Server not found']);
return;
}
$panelType = $_POST['panel_type'] ?? '';
if (!in_array($panelType, ['wg-easy', '3x-ui'])) {
http_response_code(400);
echo json_encode(['error' => 'Invalid panel type. Supported: wg-easy, 3x-ui']);
return;
}
// Handle file upload
if (!isset($_FILES['backup_file']) || $_FILES['backup_file']['error'] !== UPLOAD_ERR_OK) {
http_response_code(400);
echo json_encode(['error' => 'No backup file uploaded']);
return;
}
$backupContent = file_get_contents($_FILES['backup_file']['tmp_name']);
try {
$importer = new PanelImporter($serverId, $user['id'], $panelType);
if (!$importer->parseBackupFile($backupContent)) {
http_response_code(400);
echo json_encode(['error' => 'Invalid backup file format']);
return;
}
$result = $importer->import();
echo json_encode($result);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'success' => false,
'error' => $e->getMessage()
]);
}
});
// API: Get import history
Router::get('/api/servers/{id}/imports', function ($params) {
header('Content-Type: application/json');
$user = JWT::requireAuth();
if (!$user) return;
$serverId = (int)$params['id'];
// Validate server ownership
$server = VpnServer::getById($serverId);
if (!$server || $server['user_id'] != $user['id']) {
http_response_code(404);
echo json_encode(['error' => 'Server not found']);
return;
}
$imports = PanelImporter::getImportHistory($serverId);
echo json_encode([
'success' => true,
'imports' => $imports
]);
});
if (!$user) return;
$serverId = (int)$params['id'];