This commit is contained in:
2026-01-11 01:54:38 +01:00
parent aeea724854
commit af865bc6e7
5 changed files with 220 additions and 9 deletions

View File

@@ -312,6 +312,37 @@ class ApiKernel
return $json === false ? '' : $json;
}
private function normalizeApiName(string $value): string
{
$value = trim($value);
$value = preg_replace('/\s+/', '-', $value);
$value = preg_replace('/[^A-Za-z0-9_-]+/', '-', $value);
$value = preg_replace('/-+/', '-', $value);
return trim($value, '-');
}
private function assertTemplateApiNameUnique(
string $table,
string $apiCol,
string $idCol,
int $customerId,
string $apiName,
?int $excludeId
): void {
$sql = "SELECT COUNT(*) FROM `$table` WHERE `$apiCol` = :api AND `customer_id` = :cid";
$params = [':api' => $apiName, ':cid' => $customerId];
if ($excludeId !== null && $excludeId > 0) {
$sql .= " AND `$idCol` <> :id";
$params[':id'] = $excludeId;
}
$stmt = $this->pdo->prepare($sql);
$stmt->execute($params);
$count = (int)$stmt->fetchColumn();
if ($count > 0) {
$this->fail('api_name already exists', ['api_name' => $apiName], 409);
}
}
// =================================================================
// 🚀 CRUD HANDLER METHODEN
@@ -330,6 +361,8 @@ class ApiKernel
$descCol = $cfg['desc'] ?? $this->firstExisting($allCols, ['description', 'desc', 'descr']);
$catCol = $cfg['cat'] ?? $this->firstExisting($allCols, ['category', 'cat']);
$updCol = $cfg['upd'] ?? $this->firstExisting($allCols, ['updated_at', 'updated', 'updatedAt']);
$apiCol = null;
$apiCol = ($kind === 'templates') ? $this->firstExisting($allCols, ['api_name']) : null;
$q = trim((string)$this->val($this->in, 'q', ''));
$limit = max(1, (int)$this->val($this->in, 'limit', 500));
$offset = max(0, (int)$this->val($this->in, 'offset', 0));
@@ -378,6 +411,7 @@ class ApiKernel
'id' => $r[$idCol] ?? null,
'name' => $r[$nameCol] ?? null,
];
if ($apiCol && isset($r[$apiCol])) $item['api_name'] = $r[$apiCol];
if ($descCol && isset($r[$descCol])) $item['desc'] = $r[$descCol];
if ($catCol && isset($r[$catCol])) $item['category'] = $r[$catCol];
if ($updCol && isset($r[$updCol])) $item['updated_at'] = $r[$updCol];
@@ -481,6 +515,27 @@ class ApiKernel
$blockId = $this->val($this->in, ['block_id', 'blk_id'], null);
$data = [$nameCol => $name];
if ($kind === 'templates') {
$apiCol = $this->firstExisting($allCols, ['api_name']);
if ($apiCol) {
$apiRaw = $this->val($this->in, ['api_name', 'apiName', 'api'], null);
if ($apiRaw === null || trim((string)$apiRaw) === '') {
$apiName = $this->normalizeApiName($name);
if ($apiName === '') {
$this->fail('api_name required', null, 422);
}
} else {
$apiName = trim((string)$apiRaw);
if (preg_match('/\s/', $apiName)) {
$this->fail('api_name must not contain spaces', null, 422);
}
}
$customerId = (int)($auth['customer_id'] ?? 0);
if ($customerId <= 0) $this->fail('Customer context missing', null, 500);
$this->assertTemplateApiNameUnique($t, $apiCol, $idCol, $customerId, $apiName, null);
$data[$apiCol] = $apiName;
}
}
if ($desc !== null && $descCol) $data[$descCol] = $desc;
if ($cat !== null && $catCol) $data[$catCol] = $cat;
@@ -538,6 +593,9 @@ class ApiKernel
$newId = $this->pdo->lastInsertId();
$out = ['id' => $newId, 'name' => $name];
if (!empty($apiCol) && isset($data[$apiCol])) {
$out['api_name'] = $data[$apiCol];
}
if ($desc !== null) $out['desc'] = $desc;
if ($cat !== null) $out['category'] = $cat;
$this->respond(['ok' => true, 'kind' => $kind, 'id' => $newId, 'item' => $out, 'data' => $out]);
@@ -556,6 +614,7 @@ class ApiKernel
$descCol = $cfg['desc'] ?? $this->firstExisting($allCols, ['description', 'desc', 'descr']);
$catCol = $cfg['cat'] ?? $this->firstExisting($allCols, ['category', 'cat']);
$updCol = $cfg['upd'] ?? $this->firstExisting($allCols, ['updated_at', 'updated', 'updatedAt']);
$apiCol = ($kind === 'templates') ? $this->firstExisting($allCols, ['api_name']) : null;
$id = $this->pullId($this->in);
if ($id === null || $id === '') $this->fail('id required', null, 422);
@@ -576,6 +635,20 @@ class ApiKernel
if ($name !== null) $data[$nameCol] = (string)$name;
if ($desc !== null && $descCol) $data[$descCol] = (string)$desc;
if ($cat !== null && $catCol) $data[$catCol] = (string)$cat;
if ($apiCol) {
$apiRaw = $this->val($this->in, ['api_name', 'apiName', 'api'], null);
if ($apiRaw !== null) {
$apiName = trim((string)$apiRaw);
if ($apiName === '') $this->fail('api_name required', null, 422);
if (preg_match('/\s/', $apiName)) {
$this->fail('api_name must not contain spaces', null, 422);
}
$customerId = (int)($auth['customer_id'] ?? 0);
if ($customerId <= 0) $this->fail('Customer context missing', null, 500);
$this->assertTemplateApiNameUnique($t, $apiCol, $idCol, $customerId, $apiName, (int)$id);
$data[$apiCol] = $apiName;
}
}
$htmlDbCol = $this->firstExisting($allCols, ($kind === 'snippets' ? ['content'] : ['html', 'body', 'markup']));
$jsonDbCol = $this->firstExisting($allCols, ['json_content']);
@@ -754,8 +827,9 @@ class ApiKernel
[$idCol, $allCols] = $this->resolveIdCol('templates');
$nameCol = $this->conf['columns']['templates']['name'] ?? ($this->firstExisting($allCols, ['name']) ?: $idCol);
$apiCol = $this->firstExisting($allCols, ['api_name']);
$templateKey = $this->val($this->in, ['template', 'template_id', 'id', 'name'], '');
$templateKey = $this->val($this->in, ['api_name', 'template', 'template_id', 'id', 'name'], '');
$templateId = is_numeric($templateKey) ? (int)$templateKey : null;
$where = "WHERE `customer_id` = :cid ";
@@ -768,8 +842,13 @@ class ApiKernel
if ($name === '') {
$this->fail('template required', null, 422);
}
$where .= "AND `$nameCol` = :name ";
$params[':name'] = $name;
if ($apiCol) {
$where .= "AND `$apiCol` = :name ";
$params[':name'] = $name;
} else {
$where .= "AND `$nameCol` = :name ";
$params[':name'] = $name;
}
}
$sql = "SELECT * FROM `$templatesTable` $where LIMIT 1";
@@ -800,6 +879,7 @@ class ApiKernel
'ok' => true,
'template_id' => (int)($tpl[$idCol] ?? 0),
'name' => $tpl[$nameCol] ?? null,
'api_name' => $apiCol ? ($tpl[$apiCol] ?? null) : null,
'html' => $html,
]);
}