diff --git a/public/assets/js/ui-user.js b/public/assets/js/ui-user.js
index 03dfbe3..231249e 100644
--- a/public/assets/js/ui-user.js
+++ b/public/assets/js/ui-user.js
@@ -250,8 +250,10 @@ function fillSettingsForm(settings) {
settingsForm.bridge_token.value = settings.bridge_token || '';
settingsForm.sender_token.value = settings.sender_token || '';
settingsForm.external_api_token.value = settings.external_api_token || '';
- const tables = Array.isArray(settings.bridge_tables) ? settings.bridge_tables : [];
- settingsForm.bridge_tables ? settingsForm.bridge_tables.value = tables.join(', ') : null;
+ const tables = normalizeTableNames(settings.bridge_tables);
+ if (settingsForm.bridge_tables) {
+ settingsForm.bridge_tables.value = tables.join(', ');
+ }
applyBridgePreview(tables);
state.rotate = { bridge: false, sender: false, external: false };
}
@@ -343,7 +345,7 @@ function parseBridgeTablesInput() {
}
function applyBridgePreview(tables) {
- state.bridgeTables = Array.isArray(tables) ? tables : [];
+ state.bridgeTables = normalizeTableNames(tables);
if (!bridgePreview) return;
if (!state.bridgeTables.length) {
bridgePreview.innerHTML = 'Keine Einschränkung – alle Tabellen erlaubt.';
@@ -366,7 +368,7 @@ async function validateBridgeSettings(ev) {
try {
const res = await apiAction('account.bridge.test', { method: 'POST', data });
if (!res?.ok) throw new Error(res?.error || 'Prüfung fehlgeschlagen');
- const tables = Array.isArray(res.tables) ? res.tables : [];
+ const tables = normalizeTableNames(res.tables);
applyBridgePreview(tables);
if (settingsForm.bridge_tables) {
settingsForm.bridge_tables.value = tables.join(', ');
@@ -377,6 +379,28 @@ async function validateBridgeSettings(ev) {
}
}
+function normalizeTableNames(list) {
+ if (!Array.isArray(list)) return [];
+ const seen = new Set();
+ const result = [];
+ for (const entry of list) {
+ let name = '';
+ if (typeof entry === 'string') {
+ name = entry;
+ } else if (entry && typeof entry === 'object') {
+ name = entry.name || entry.table || entry.label || '';
+ }
+ if (typeof name === 'string') {
+ const trimmed = name.trim();
+ if (trimmed && !seen.has(trimmed)) {
+ seen.add(trimmed);
+ result.push(trimmed);
+ }
+ }
+ }
+ return result;
+}
+
async function loadUsers() {
try {
const res = await apiAction('account.users.list', { method: 'GET' });
diff --git a/src/ApiKernel.php b/src/ApiKernel.php
index 6d82931..aaf34c6 100644
--- a/src/ApiKernel.php
+++ b/src/ApiKernel.php
@@ -2011,9 +2011,10 @@ class ApiKernel
private function ensureCustomerSettingsTableExists(): void
{
$table = $this->customerSettingsTable();
- if ($this->tableExists($table)) return;
- try {
- $sql = <<tableExists($table)) {
+ try {
+ $sql = <<pdo->exec($sql);
- $this->tableExistsCache[$table] = true;
+ $this->pdo->exec($sql);
+ $this->tableExistsCache[$table] = true;
+ $justCreated = true;
+ } catch (Throwable $e) {
+ $this->fail('Customer-Settings Tabelle fehlt und konnte nicht erstellt werden', $e->getMessage(), 500);
+ }
+ }
+
+ if ($justCreated) {
+ return;
+ }
+
+ $this->ensureCustomerSettingsColumns($table);
+ }
+
+ private function ensureCustomerSettingsColumns(string $table): void
+ {
+ try {
+ $columns = $this->tableColumns($table);
} catch (Throwable $e) {
- $this->fail('Customer-Settings Tabelle fehlt und konnte nicht erstellt werden', $e->getMessage(), 500);
+ $this->fail('Customer-Settings Tabelle konnte nicht gelesen werden', $e->getMessage(), 500);
+ return;
+ }
+
+ $missing = [];
+
+ if (!in_array('bridge_tables', $columns, true)) {
+ $missing[] = 'ADD COLUMN `bridge_tables` text DEFAULT NULL';
+ }
+
+ if (!$missing) {
+ return;
+ }
+
+ try {
+ $sql = 'ALTER TABLE `' . $table . '` ' . implode(', ', $missing);
+ $this->pdo->exec($sql);
+ } catch (Throwable $e) {
+ $this->fail('Customer-Settings Tabelle konnte nicht aktualisiert werden', $e->getMessage(), 500);
}
}