From 8e6248cea1fcec20eab831752bc96dfe0c2dd53c Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Tue, 20 Jan 2026 01:44:49 +0100 Subject: [PATCH] update --- .../accountsetup/accountsetup_config.php | 1 + .../landingpage/accountsetup/settings.php | 34 ------ partials/landingpage/accountsetup/system.php | 53 +++++++++ public/admin/system.php | 2 + public/assets/js/ui-create.js | 2 +- public/assets/js/ui-user.js | 30 ++--- src/ApiKernel.php | 112 ++++++++++++++---- 7 files changed, 158 insertions(+), 76 deletions(-) create mode 100644 partials/landingpage/accountsetup/system.php create mode 100644 public/admin/system.php diff --git a/partials/landingpage/accountsetup/accountsetup_config.php b/partials/landingpage/accountsetup/accountsetup_config.php index 89eeaa3..e2fb342 100644 --- a/partials/landingpage/accountsetup/accountsetup_config.php +++ b/partials/landingpage/accountsetup/accountsetup_config.php @@ -3,6 +3,7 @@ $appBaseUrl = $GLOBALS['app_base_url'] ?? ''; $defaultNavLinks = [ ['id' => 'dashboard', 'label' => 'Dashboard', 'href' => $appBaseUrl . '/admin/dashboard.php'], + ['id' => 'system', 'label' => 'Systemeinstellungen', 'href' => $appBaseUrl . '/admin/system.php'], ['id' => 'settings', 'label' => 'API & Tabellen', 'href' => $appBaseUrl . '/admin/settings.php'], ['id' => 'users', 'label' => 'Userverwaltung', 'href' => $appBaseUrl . '/admin/users.php'], ['id' => 'profile', 'label' => 'Mein Konto', 'href' => $appBaseUrl . '/admin/profile.php'], diff --git a/partials/landingpage/accountsetup/settings.php b/partials/landingpage/accountsetup/settings.php index 467b4b9..e661357 100644 --- a/partials/landingpage/accountsetup/settings.php +++ b/partials/landingpage/accountsetup/settings.php @@ -68,11 +68,6 @@ require dirname(__DIR__) . '/../structure/layout_start.php'; - -
@@ -83,20 +78,6 @@ require dirname(__DIR__) . '/../structure/layout_start.php'; -
-
-
-

Sections verwalten

-

Die Sortierung steuert, welche Inhalte in anderen Sections eingebunden werden dürfen.

-
-
-
- - -
-
    -
    -
    @@ -267,21 +248,6 @@ require dirname(__DIR__) . '/../structure/layout_start.php';
    - -
    -
    -

    Section löschen

    - -
    -

    - - -
    - -
    -
    -
    -

    Beispiel: Mapping einer Config-Datei

    diff --git a/partials/landingpage/accountsetup/system.php b/partials/landingpage/accountsetup/system.php new file mode 100644 index 0000000..4fe5b74 --- /dev/null +++ b/partials/landingpage/accountsetup/system.php @@ -0,0 +1,53 @@ + +
    +
    +

    Standard-Editor

    +

    Standardauswahl für neue Inhalte. Kann pro Element spaeter angepasst werden.

    + + + +
    + +
    + +
    + +
    +
    +
    +

    Sections verwalten

    +

    Die Sortierung steuert, welche Inhalte in anderen Sections eingebunden werden duerfen.

    +
    +
    +
    + + +
    +
      +
      +
      + + +
      +
      +

      Section loeschen

      + +
      +

      + + +
      + +
      +
      +
      + diff --git a/public/admin/system.php b/public/admin/system.php new file mode 100644 index 0000000..c3f29ad --- /dev/null +++ b/public/admin/system.php @@ -0,0 +1,2 @@ +tableMap['content_sections'] ?? $this->lookupTableName('content_sections', 'emailtemplate_content_sections'); } + private function resolveContentItemColumns(string $table): array + { + $cols = $this->tableColumns($table); + return [ + 'category' => $this->firstExisting($cols, ['category', 'cat']), + 'html' => $this->firstExisting($cols, ['html', 'html_content', 'body', 'markup', 'content']), + 'json' => $this->firstExisting($cols, ['json_content']), + 'editor' => $this->firstExisting($cols, ['editor_type', 'editor']), + 'craft' => $this->firstExisting($cols, ['craft_json', 'craft_content', 'craft_data']), + 'settings' => $this->firstExisting($cols, ['settings_json', 'settings']), + ]; + } + private function useUnifiedContent(): bool { return $this->tableExists($this->contentItemsTable()) && $this->tableExists($this->contentSectionsTable()); @@ -514,6 +527,10 @@ class ApiKernel if (!$this->tableExists($itemsTable) || !$this->tableExists($sectionsTable)) { $this->fail('Content tables not available', null, 500); } + $itemCols = $this->resolveContentItemColumns($itemsTable); + $catCol = $itemCols['category']; + $htmlCol = $itemCols['html']; + $jsonCol = $itemCols['json']; $section = $fixedSection ?: $this->resolveSectionFromInput($customerId); $q = trim((string)$this->val($this->in, 'q', '')); @@ -527,7 +544,11 @@ class ApiKernel $params[':sid'] = (int)$section['id']; } if ($q !== '') { - $where .= " AND (i.`name` LIKE :q OR i.`category` LIKE :q) "; + $where .= " AND (i.`name` LIKE :q"; + if ($catCol) { + $where .= " OR i.`$catCol` LIKE :q"; + } + $where .= ") "; $params[':q'] = '%' . $q . '%'; } @@ -550,7 +571,7 @@ class ApiKernel 'id' => $r['id'] ?? null, 'name' => $r['name'] ?? null, 'api_name' => $r['api_name'] ?? null, - 'category' => $r['category'] ?? null, + 'category' => $catCol ? ($r[$catCol] ?? null) : null, 'section_id' => $r['section_id'] ?? null, 'section_name' => $r['section_name'] ?? null, 'section_slug' => $r['section_slug'] ?? null, @@ -559,8 +580,8 @@ class ApiKernel 'updated_at' => $r['updated_at'] ?? null, 'created_at' => $r['created_at'] ?? null, ]; - if (array_key_exists('html', $r)) $item['html'] = (string)($r['html'] ?? ''); - if (array_key_exists('json_content', $r)) $item['content'] = $r['json_content']; + if ($htmlCol && array_key_exists($htmlCol, $r)) $item['html'] = (string)($r[$htmlCol] ?? ''); + if ($jsonCol && array_key_exists($jsonCol, $r)) $item['content'] = $r[$jsonCol]; $out[] = $item; } @@ -588,6 +609,11 @@ class ApiKernel if (!$this->tableExists($itemsTable) || !$this->tableExists($sectionsTable)) { $this->fail('Content tables not available', null, 500); } + $itemCols = $this->resolveContentItemColumns($itemsTable); + $htmlCol = $itemCols['html']; + $jsonCol = $itemCols['json']; + $craftCol = $itemCols['craft']; + $editorCol = $itemCols['editor']; $section = $fixedSection ?: $this->resolveSectionFromInput($customerId); $params = [':cid' => $customerId, ':id' => $id]; @@ -608,8 +634,8 @@ class ApiKernel $row = $stmt->fetch(); if (!$row) $this->fail('Not found', ['id' => $id], 404); - $html = (string)($row['html'] ?? ''); - $json = $row['json_content'] ?? null; + $html = $htmlCol ? (string)($row[$htmlCol] ?? '') : ''; + $json = $jsonCol ? ($row[$jsonCol] ?? null) : null; $gjsComponents = []; if ($json !== null) { $decoded = json_decode((string)$json, true); @@ -635,8 +661,8 @@ class ApiKernel 'html' => $html, 'content' => $json, 'gjs_components' => $gjsComponents, - 'editor_type' => $row['editor_type'] ?? null, - 'craft_json' => $row['craft_json'] ?? null, + 'editor_type' => $editorCol ? ($row[$editorCol] ?? null) : null, + 'craft_json' => $craftCol ? ($row[$craftCol] ?? null) : null, ]); } @@ -650,6 +676,13 @@ class ApiKernel if (!$this->tableExists($itemsTable)) { $this->fail('Content table not available', null, 500); } + $itemCols = $this->resolveContentItemColumns($itemsTable); + $catCol = $itemCols['category']; + $htmlCol = $itemCols['html']; + $jsonCol = $itemCols['json']; + $editorCol = $itemCols['editor']; + $craftCol = $itemCols['craft']; + $settingsCol = $itemCols['settings']; $name = trim((string)$this->val($this->in, ['name', 'title'], '')); if ($name === '') $this->fail('name required', null, 422); @@ -683,22 +716,27 @@ class ApiKernel 'name' => $name, 'api_name' => $apiName, ]; - if ($category !== null) $data['category'] = (string)$category; - if ($editorType !== '') $data['editor_type'] = $editorType; - if ($craftJson !== null) $data['craft_json'] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson); - if ($settings !== null) $data['settings_json'] = is_string($settings) ? $settings : $this->encodeJson($settings); + if ($category !== null && $catCol) $data[$catCol] = (string)$category; + if ($editorType !== '' && $editorCol) $data[$editorCol] = $editorType; + if ($craftJson !== null && $craftCol) $data[$craftCol] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson); + if ($settings !== null && $settingsCol) $data[$settingsCol] = is_string($settings) ? $settings : $this->encodeJson($settings); if ($json !== null) { + if (!$jsonCol) $this->fail('json_content column missing', null, 500); $components = is_string($json) ? json_decode($json, true) : $json; if (is_array($components)) { $components = $this->cleanReferenceComponents($components); - $data['json_content'] = $this->encodeJson($components); + $data[$jsonCol] = $this->encodeJson($components); } else { - $data['json_content'] = is_string($json) ? $json : ''; + $data[$jsonCol] = is_string($json) ? $json : ''; + } + if ($html !== null) { + if (!$htmlCol) $this->fail('html column missing', null, 500); + $data[$htmlCol] = (string)$html; } - if ($html !== null) $data['html'] = (string)$html; } elseif ($html !== null) { - $data['html'] = (string)$html; + if (!$htmlCol) $this->fail('html column missing', null, 500); + $data[$htmlCol] = (string)$html; } $columns = array_keys($data); @@ -721,6 +759,13 @@ class ApiKernel if (!$this->tableExists($itemsTable)) { $this->fail('Content table not available', null, 500); } + $itemCols = $this->resolveContentItemColumns($itemsTable); + $catCol = $itemCols['category']; + $htmlCol = $itemCols['html']; + $jsonCol = $itemCols['json']; + $editorCol = $itemCols['editor']; + $craftCol = $itemCols['craft']; + $settingsCol = $itemCols['settings']; $id = $this->pullId($this->in); if ($id === null || $id === '') $this->fail('id required', null, 422); @@ -741,7 +786,7 @@ class ApiKernel if ($name !== null) $data['name'] = (string)$name; $category = $this->val($this->in, ['category', 'cat'], null); - if ($category !== null) $data['category'] = (string)$category; + if ($category !== null && $catCol) $data[$catCol] = (string)$category; $apiRaw = $this->val($this->in, ['api_name', 'apiName', 'api'], null); $apiName = $apiRaw !== null ? $this->normalizeApiName((string)$apiRaw) : null; @@ -769,24 +814,29 @@ class ApiKernel $html = $this->val($this->in, ['html', 'body', 'markup', 'content'], null); $json = $this->val($this->in, ['content_json', 'json', 'structure_json'], null); if ($json !== null) { + if (!$jsonCol) $this->fail('json_content column missing', null, 500); $components = is_string($json) ? json_decode($json, true) : $json; if (is_array($components)) { $components = $this->cleanReferenceComponents($components); - $data['json_content'] = $this->encodeJson($components); + $data[$jsonCol] = $this->encodeJson($components); } else { - $data['json_content'] = is_string($json) ? $json : ''; + $data[$jsonCol] = is_string($json) ? $json : ''; + } + if ($html !== null) { + if (!$htmlCol) $this->fail('html column missing', null, 500); + $data[$htmlCol] = (string)$html; } - if ($html !== null) $data['html'] = (string)$html; } elseif ($html !== null) { - $data['html'] = (string)$html; + if (!$htmlCol) $this->fail('html column missing', null, 500); + $data[$htmlCol] = (string)$html; } $editorType = $this->val($this->in, ['editor_type', 'editor'], null); - if ($editorType !== null) $data['editor_type'] = strtolower(trim((string)$editorType)); + if ($editorType !== null && $editorCol) $data[$editorCol] = strtolower(trim((string)$editorType)); $craftJson = $this->val($this->in, ['craft_json', 'craft_content', 'craft_data'], null); - if ($craftJson !== null) $data['craft_json'] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson); + if ($craftJson !== null && $craftCol) $data[$craftCol] = is_string($craftJson) ? $craftJson : $this->encodeJson($craftJson); $settings = $this->val($this->in, ['settings_json', 'settings'], null); - if ($settings !== null) $data['settings_json'] = is_string($settings) ? $settings : $this->encodeJson($settings); + if ($settings !== null && $settingsCol) $data[$settingsCol] = is_string($settings) ? $settings : $this->encodeJson($settings); if (!$data) { $this->respond(['ok' => true, 'kind' => 'content', 'id' => $id, 'updated' => true]); @@ -2313,7 +2363,17 @@ class ApiKernel return null; } $itemsTable = $this->contentItemsTable(); - $sql = "SELECT `html`,`json_content` FROM `$itemsTable` WHERE `customer_id` = :cid AND `section_id` = :sid AND `id` = :id LIMIT 1"; + $itemCols = $this->resolveContentItemColumns($itemsTable); + $htmlCol = $itemCols['html']; + $jsonCol = $itemCols['json']; + if (!$htmlCol && !$jsonCol) { + $cache[$cacheKey] = null; + return null; + } + $selectCols = []; + if ($htmlCol) $selectCols[] = "`$htmlCol`"; + if ($jsonCol) $selectCols[] = "`$jsonCol`"; + $sql = "SELECT " . implode(',', $selectCols) . " FROM `$itemsTable` WHERE `customer_id` = :cid AND `section_id` = :sid AND `id` = :id LIMIT 1"; $stmt = $this->pdo->prepare($sql); $stmt->execute([':cid' => $customerId, ':sid' => (int)$section['id'], ':id' => $id]); $row = $stmt->fetch(); @@ -2321,7 +2381,7 @@ class ApiKernel $cache[$cacheKey] = null; return null; } - $html = (string)($row['html'] ?? ''); + $html = $htmlCol ? (string)($row[$htmlCol] ?? '') : ''; } else { if (!$kindKey) return null; $table = $this->tableMap[$kindKey] ?? null;