Actualiser api/index.php
CI / PHP Syntax Check (push) Has been cancelled
CI / JavaScript Lint (push) Has been cancelled
CI / Docker Build Test (push) Has been cancelled
CI / Validate Translation Files (push) Has been cancelled
CI / Auto-merge develop → main (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
Security Scan (Trivy) / Trivy — Docker image scan (push) Has been cancelled
Security Scan (Trivy) / Trivy — Filesystem scan (push) Has been cancelled

This commit is contained in:
2026-06-17 12:25:06 +00:00
parent 495d7a22eb
commit b97845553e
+84
View File
@@ -920,6 +920,15 @@ try {
case 'app_settings_save': case 'app_settings_save':
appSettingsSave($db); appSettingsSave($db);
break; break;
case 'locations_list':
locationsList($db);
break;
case 'locations_add':
locationsAdd($db);
break;
case 'locations_remove':
locationsRemove($db);
break;
case 'recipes_list': case 'recipes_list':
recipesList($db); recipesList($db);
break; break;
@@ -11949,6 +11958,81 @@ function familySiblingSuggest(PDO $db): void {
], JSON_UNESCAPED_UNICODE); ], JSON_UNESCAPED_UNICODE);
} }
// ===== CUSTOM LOCATIONS =====
function locationsList(PDO $db): void {
$rows = $db->query("SELECT key, label, icon, sort_order, is_builtin FROM locations ORDER BY sort_order ASC, id ASC")->fetchAll();
echo json_encode(['success' => true, 'locations' => $rows]);
}
function locationsAdd(PDO $db): void {
$input = json_decode(file_get_contents('php://input'), true) ?? [];
$label = trim($input['label'] ?? '');
$icon = trim($input['icon'] ?? '📦');
if ($label === '') {
echo json_encode(['success' => false, 'error' => 'label required']);
return;
}
// Generate a safe key from the label (slug-like, ASCII-only)
$key = mb_strtolower(trim($label));
$key = preg_replace('/[^a-z0-9]+/u', '_', $key);
$key = trim($key, '_');
if ($key === '') {
echo json_encode(['success' => false, 'error' => 'invalid label']);
return;
}
$stmt = $db->prepare("SELECT id FROM locations WHERE key = ?");
$stmt->execute([$key]);
if ($stmt->fetch()) {
echo json_encode(['success' => false, 'error' => 'location already exists']);
return;
}
$maxOrder = (int)$db->query("SELECT COALESCE(MAX(sort_order), 0) FROM locations")->fetchColumn();
$stmt = $db->prepare("INSERT INTO locations (key, label, icon, sort_order, is_builtin) VALUES (?, ?, ?, ?, 0)");
$stmt->execute([$key, $label, $icon, $maxOrder + 1]);
echo json_encode(['success' => true, 'key' => $key]);
}
function locationsRemove(PDO $db): void {
$input = json_decode(file_get_contents('php://input'), true) ?? [];
$key = trim($input['key'] ?? '');
if ($key === '') {
echo json_encode(['success' => false, 'error' => 'key required']);
return;
}
$stmt = $db->prepare("SELECT is_builtin FROM locations WHERE key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
if (!$row) {
echo json_encode(['success' => false, 'error' => 'location not found']);
return;
}
if ((int)$row['is_builtin'] === 1) {
echo json_encode(['success' => false, 'error' => 'cannot delete a builtin location']);
return;
}
// Guard: refuse deletion if inventory items still reference this location
$stmt = $db->prepare("SELECT COUNT(*) FROM inventory WHERE location = ? AND quantity > 0");
$stmt->execute([$key]);
if ((int)$stmt->fetchColumn() > 0) {
echo json_encode(['success' => false, 'error' => 'location still has items in inventory']);
return;
}
$db->prepare("DELETE FROM locations WHERE key = ?")->execute([$key]);
echo json_encode(['success' => true]);
}
// ===== SHARED APP DATA FUNCTIONS ===== // ===== SHARED APP DATA FUNCTIONS =====
function appSettingsGet(PDO $db): void { function appSettingsGet(PDO $db): void {