From 45ed70319a16382b2b0fa837720c7584a94e6f24 Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Tue, 9 Dec 2025 00:51:38 +0100 Subject: [PATCH] asdasd --- download/emailtemplate_bridge.php | 2 + partials/landingpage/admin/bridge.php | 41 ++++++++++++++++++-- public/assets/js/bridge-setup-page.js | 55 +++++++++++++++++++-------- src/ApiKernel.php | 21 +++++++++- 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/download/emailtemplate_bridge.php b/download/emailtemplate_bridge.php index 634c185..6dff67b 100644 --- a/download/emailtemplate_bridge.php +++ b/download/emailtemplate_bridge.php @@ -33,6 +33,7 @@ $bridgeConfig = [ ], ], 'tables_allow' => [], // optional whitelist: ['customers', 'orders'] + 'setup_hint' => '__SETUP_HINT__', ]; // {{BRIDGE_DB_SETUP}} @@ -199,6 +200,7 @@ while ($row = $tablesStmt->fetch(PDO::FETCH_NUM)) { bridgeRespond([ 'ok' => true, 'tables' => $tables, + 'setup_hint' => $bridgeConfig['setup_hint'] ?? null, 'fetched' => date(DATE_ATOM), ]); } catch (Throwable $e) { diff --git a/partials/landingpage/admin/bridge.php b/partials/landingpage/admin/bridge.php index 91e80ba..5760499 100644 --- a/partials/landingpage/admin/bridge.php +++ b/partials/landingpage/admin/bridge.php @@ -111,6 +111,7 @@ $debugRedirect = isset($_GET['debug_redirect']);

Relativ zur Bridge-Datei oder absolut. Die Datei sollte ein Array oder Objekt mit den Zugangsdaten liefern.

+
@@ -153,9 +154,43 @@ $debugRedirect = isset($_GET['debug_redirect']); -
+
- - + +
+

Beispiel: Mapping einer Config-Datei

+

Angenommen, deine ../config/database.php liefert folgendes Array:

+
 [
+        'connections' => [
+            'default' => [
+                'host' => '127.0.0.1',
+                'port' => 3306,
+                'database' => 'kunden_db',
+                'username' => 'dbuser',
+                'password' => 'secret',
+                'charset' => 'utf8mb4',
+            ],
+        ],
+    ],
+];
+PHP, ENT_QUOTES); ?>
+

Dann trägst du ein:

+
    +
  • Pfad zur Konfigurationsdatei: ../config/database.php
  • +
  • Basis-Pfad: database.connections.default
  • +
  • Host-/Port-/DB-/User-/Pass-/Charset-Key: jeweils host, port, database, username, password, charset
  • +
+

Die Bridge liest dann automatisch die Werte aus diesem Array und baut daraus den DSN.

+
+ +
+
+
+ + + diff --git a/public/assets/js/bridge-setup-page.js b/public/assets/js/bridge-setup-page.js index 2143e59..4b985d6 100644 --- a/public/assets/js/bridge-setup-page.js +++ b/public/assets/js/bridge-setup-page.js @@ -15,6 +15,8 @@ let statusLabel; let loadBtn; let importBtn; let importInput; +let configExampleBtn; +let configExampleDialog; export function initBridgeSetupPage() { form = document.getElementById('bridgeSetupForm'); @@ -27,6 +29,8 @@ export function initBridgeSetupPage() { loadBtn = document.getElementById('btn-load-remote'); importBtn = document.getElementById('btn-import-bridge'); importInput = document.getElementById('bridgeImportInput'); + configExampleBtn = document.getElementById('btn-config-example'); + configExampleDialog = document.getElementById('configExampleDialog'); modeInputs = Array.from(form.querySelectorAll('input[name="db_mode"]')); form.addEventListener('submit', submitBridgeSetup); @@ -34,6 +38,9 @@ export function initBridgeSetupPage() { loadBtn?.addEventListener('click', loadTablesFromBridge); importBtn?.addEventListener('click', () => importInput?.click()); importInput?.addEventListener('change', handleBridgeImport); + configExampleBtn?.addEventListener('click', () => { + if (configExampleDialog?.showModal) configExampleDialog.showModal(); + }); modeInputs.forEach(input => { input.addEventListener('change', () => applyModeVisibility(input.value)); }); @@ -71,8 +78,7 @@ async function loadBridgeSetup() { try { const res = await apiAction('account.bridge.setup.get', { method: 'GET' }); if (!res?.ok) throw new Error(res?.error || 'Bridge-Setup konnte nicht geladen werden'); - state.setup = res.setup || defaultSetup(); - fillForm(state.setup); + fillForm(res.setup || state.setup || defaultSetup()); updateStatus('Daten geladen.'); } catch (err) { console.error(err); @@ -83,10 +89,11 @@ async function loadBridgeSetup() { } function fillForm(setup) { - const data = { ...defaultSetup(), ...(setup || {}) }; + const data = normalizeSetupInput(setup); + state.setup = data; if (tablesInput) { - tablesInput.value = (data.tables || []).join(', '); - updateTablesPreview(parseTablesInput()); + tablesInput.value = data.tables.join(', '); + updateTablesPreview(data.tables); } const activeMode = (data.mode || 'direct').toLowerCase(); modeInputs.forEach(input => { @@ -137,9 +144,7 @@ async function handleBridgeImport(ev) { toast('Bridge-Datei konnte nicht erkannt werden', false); return; } - state.setup = { ...defaultSetup(), ...state.setup, ...parsed }; - fillForm(state.setup); - updateTablesPreview(parseTablesInput()); + fillForm({ ...state.setup, ...parsed }); updateStatus('Bridge-Datei importiert'); toast('Bridge-Daten übernommen', true); } catch (err) { @@ -203,8 +208,7 @@ async function submitBridgeSetup(ev) { try { const res = await apiAction('account.bridge.setup.save', { method: 'POST', data: payload }); if (!res?.ok) throw new Error(res?.error || 'Bridge-Setup konnte nicht gespeichert werden'); - state.setup = res.setup || payload; - fillForm(state.setup); + fillForm(res.setup || payload); updateStatus('Bridge-Setup gespeichert.'); toast('Bridge-Setup gespeichert', true); } catch (err) { @@ -220,12 +224,20 @@ async function loadTablesFromBridge(ev) { try { const res = await apiAction('account.bridge.test', { method: 'POST', data: {} }); if (!res?.ok) throw new Error(res?.error || 'Bridge konnte nicht abgefragt werden'); - const tables = normalizeTableNames(res.tables); - if (tablesInput) { - tablesInput.value = tables.join(', '); - updateTablesPreview(tables); + const fetchedTables = normalizeTableNames(res.tables); + const allowedTables = normalizeTableNames(res.setup_hint?.tables ?? fetchedTables); + const merged = { + ...(state.setup || {}), + tables: allowedTables, + ...(res.setup_hint || {}), + }; + if (res.setup_hint) { + merged.mode = res.setup_hint.mode || merged.mode; + merged.direct = { ...(merged.direct || {}), ...(res.setup_hint.direct || {}) }; + merged.config = { ...(merged.config || {}), ...(res.setup_hint.config || {}) }; } - updateStatus(`Tabellen geladen (${tables.length}).`); + fillForm(merged); + updateStatus(`Tabellen geladen (${fetchedTables.length}).`); toast('Tabellen erfolgreich geladen', true); } catch (err) { console.error(err); @@ -344,3 +356,16 @@ function parseBridgeBasePath(snippet) { const match = snippet.match(regex); return match ? match[1] : ''; } + +function normalizeSetupInput(input) { + const base = defaultSetup(); + if (!input || typeof input !== 'object') return base; + const mode = (input.mode || base.mode).toLowerCase(); + const validMode = mode === 'config' ? 'config' : 'direct'; + const tables = normalizeTableNames(input.tables || base.tables); + const direct = { ...base.direct, ...(input.direct || {}) }; + direct.port = Number(direct.port || 3306) || 3306; + direct.charset = direct.charset || 'utf8mb4'; + const config = { ...base.config, ...(input.config || {}) }; + return { tables, mode: validMode, direct, config }; +} diff --git a/src/ApiKernel.php b/src/ApiKernel.php index 174b1b3..59109ae 100644 --- a/src/ApiKernel.php +++ b/src/ApiKernel.php @@ -1895,6 +1895,7 @@ class ApiKernel $this->respond([ 'ok' => true, 'tables' => $schema['tables'] ?? [], + 'setup_hint' => $schema['setup_hint'] ?? null, 'fetched' => $schema['fetched'] ?? date(DATE_ATOM), ]); } @@ -1933,7 +1934,11 @@ class ApiKernel private function getBridgeSetupData(int $customerId): array { $settings = $this->getCustomerSettings($customerId); - return $settings['bridge_setup'] ?? $this->defaultBridgeSetup(); + $setup = $settings['bridge_setup'] ?? $this->defaultBridgeSetup(); + if ((!$setup['tables'] || !count($setup['tables'])) && !empty($settings['bridge_tables'])) { + $setup['tables'] = $this->normalizeBridgeTables($settings['bridge_tables']); + } + return $setup; } private function saveCustomerSettings(int $customerId, array $data): array @@ -2555,6 +2560,15 @@ SQL; $content = preg_replace("/'pass'\\s*=>\\s*'[^']*',/", "'pass' => {$passValue},", $content, 1); } + $setupHint = [ + 'mode' => $setup['mode'] ?? 'direct', + 'tables' => $tables, + 'direct' => $setup['direct'] ?? [], + 'config' => $setup['config'] ?? [], + ]; + $setupExport = $this->exportPhpValue($setupHint); + $content = str_replace("'setup_hint' => '__SETUP_HINT__',", "'setup_hint' => {$setupExport},", $content); + $snippet = $this->buildBridgeSetupSnippet($setup); if (strpos($content, '// {{BRIDGE_DB_SETUP}}') !== false) { $content = str_replace('// {{BRIDGE_DB_SETUP}}', $snippet, $content); @@ -2708,6 +2722,11 @@ SQL; return '[' . implode(', ', $escaped) . ']'; } + private function exportPhpValue($value): string + { + return var_export($value, true); + } + private function bridgeDownloadTemplate(): string { return <<<'PHP'