From cb75558581642ebf09b232dc07955efc613584b3 Mon Sep 17 00:00:00 2001 From: dadaloop82 Date: Mon, 27 Apr 2026 17:33:49 +0000 Subject: [PATCH] fix: auto-migrate Bring! names to generic on every list load (throttled 10min) - bringGetList() now runs bringMigrateNamesInternal() silently after returning the response, max once per 10 minutes (bring_migrate_ts.json flag) - Refactored migration into bringMigrateNamesInternal() reusable function - Removed manual migrate button from UI (not needed, it's automatic now) - One-shot migration already executed via curl: 16 items updated in Bring! --- api/index.php | 139 +++++++++++++++++++++++++++----------------------- index.html | 6 --- 2 files changed, 74 insertions(+), 71 deletions(-) diff --git a/api/index.php b/api/index.php index cb83c1e..cba4bcf 100644 --- a/api/index.php +++ b/api/index.php @@ -4051,17 +4051,30 @@ function bringGetList(): void { 'purchase' => $purchase, 'recently' => $recently, ], JSON_UNESCAPED_UNICODE); + + // ── Background auto-migration ───────────────────────────────────────── + // After sending the response, silently migrate any item that still uses + // the specific product name instead of the generic shopping_name. + // This runs at most once every 10 minutes (flag file throttle) to avoid + // hammering the Bring! API on every page load. + $flagFile = __DIR__ . '/../data/bring_migrate_ts.json'; + $doMigrate = true; + if (file_exists($flagFile)) { + $ts = (int)(json_decode(file_get_contents($flagFile), true)['ts'] ?? 0); + if ((time() - $ts) < 600) $doMigrate = false; + } + if ($doMigrate) { + file_put_contents($flagFile, json_encode(['ts' => time()])); + // Use a global PDO instance if available, otherwise open a new connection + global $db; + if ($db instanceof PDO) { + bringMigrateNamesInternal($db, $data['purchase'] ?? [], $listUUID); + } + } } function bringAddItems(): void { $auth = bringAuth(); - if (!$auth) { - echo json_encode(['success' => false, 'error' => 'Credenziali Bring! non configurate']); - return; - } - - $input = json_decode(file_get_contents('php://input'), true); - $items = $input['items'] ?? []; $listUUID = $input['listUUID'] ?? $auth['bringListUUID']; if (empty($listUUID)) { @@ -4200,11 +4213,57 @@ function bringCleanSpecs(): void { } /** - * Migrate existing Bring! list items to use generic shopping names. - * For each item on the list that matches a product in the DB, if the item name - * is the specific product name (not the generic shopping_name), replace it with - * the generic name and move the specific name to the specification field. + * Core migration logic: iterate $purchaseItems and replace specific product + * names with generic shopping_name in the Bring! list identified by $listUUID. + * Returns ['migrated'=>int, 'skipped'=>int, 'errors'=>int]. */ +function bringMigrateNamesInternal(PDO $db, array $purchaseItems, string $listUUID): array { + // Build lookup: product name (lowercase) → [shopping_name, brand] + $products = $db->query("SELECT name, brand, shopping_name FROM products WHERE shopping_name IS NOT NULL AND shopping_name != ''")->fetchAll(); + $lookup = []; + foreach ($products as $p) { + $lookup[mb_strtolower($p['name'])] = ['shopping_name' => $p['shopping_name'], 'brand' => $p['brand'] ?? '']; + } + + $migrated = 0; + $skipped = 0; + $errors = 0; + + foreach ($purchaseItems as $item) { + $rawName = $item['name'] ?? ''; + $itName = bringToItalian($rawName); + $key = mb_strtolower($itName); + $spec = $item['specification'] ?? ''; + + if (!isset($lookup[$key])) { $skipped++; continue; } + + $shoppingName = $lookup[$key]['shopping_name']; + $brand = $lookup[$key]['brand']; + + // Already using the generic name → nothing to do + if (mb_strtolower($rawName) === mb_strtolower($shoppingName)) { $skipped++; continue; } + if (mb_strtolower($itName) === mb_strtolower($shoppingName)) { $skipped++; continue; } + + // Build spec: "Specific Name · Brand" + $newSpec = $itName . ($brand ? " · {$brand}" : ''); + if ($spec !== '' && $spec !== $newSpec && stripos($spec, $itName) === false) { + $newSpec = $itName . ($brand ? " · {$brand}" : '') . ' — ' . $spec; + } + + // Remove old item, add with generic name + bringRequest('DELETE', "https://api.getbring.com/rest/v2/bringlists/{$listUUID}/{$rawName}"); + $addBody = http_build_query([ + 'uuid' => $listUUID, + 'purchase' => $shoppingName, + 'specification' => $newSpec, + ]); + $result = bringRequest('PUT', "https://api.getbring.com/rest/v2/bringlists/{$listUUID}", $addBody); + if ($result !== false) { $migrated++; } else { $errors++; } + } + + return ['migrated' => $migrated, 'skipped' => $skipped, 'errors' => $errors]; +} + function bringMigrateNames(PDO $db): void { $auth = bringAuth(); if (!$auth) { @@ -4216,68 +4275,18 @@ function bringMigrateNames(PDO $db): void { echo json_encode(['success' => false, 'error' => 'Lista non trovata']); return; } - $data = bringRequest('GET', "https://api.getbring.com/rest/v2/bringlists/{$listUUID}"); if (!$data || !isset($data['purchase'])) { echo json_encode(['success' => false, 'error' => 'Errore nel recupero della lista']); return; } - // Build a lookup: product name (lowercase) → [shopping_name, brand] - $products = $db->query("SELECT name, brand, shopping_name FROM products WHERE shopping_name IS NOT NULL AND shopping_name != ''")->fetchAll(); - $lookup = []; - foreach ($products as $p) { - $lookup[mb_strtolower($p['name'])] = ['shopping_name' => $p['shopping_name'], 'brand' => $p['brand'] ?? '']; - } + $result = bringMigrateNamesInternal($db, $data['purchase'], $listUUID); - $migrated = 0; - $skipped = 0; - $errors = 0; + // Reset throttle so next bring_list load re-checks + @unlink(__DIR__ . '/../data/bring_migrate_ts.json'); - foreach ($data['purchase'] as $item) { - $rawName = $item['name'] ?? ''; - $itName = bringToItalian($rawName); // translate from Bring internal name if needed - $key = mb_strtolower($itName); - $spec = $item['specification'] ?? ''; - - if (!isset($lookup[$key])) { $skipped++; continue; } - - $shoppingName = $lookup[$key]['shopping_name']; - $brand = $lookup[$key]['brand']; - - // Already using the generic name → nothing to do - if (mb_strtolower($rawName) === mb_strtolower($shoppingName)) { $skipped++; continue; } - if (mb_strtolower(bringToItalian($rawName)) === mb_strtolower($shoppingName)) { $skipped++; continue; } - - // Build new spec: "Specific Name · Brand" (keep existing spec if already set & different) - $newSpec = $itName . ($brand ? " · {$brand}" : ''); - if ($spec !== '' && $spec !== $newSpec && stripos($spec, $itName) === false) { - // There's a custom spec the user wrote — prepend the product name - $newSpec = $itName . ($brand ? " · {$brand}" : '') . ' — ' . $spec; - } - - // Step 1: remove old item - $removeBody = http_build_query([ - 'uuid' => $listUUID, - 'purchase' => $rawName, - ]); - bringRequest('DELETE', "https://api.getbring.com/rest/v2/bringlists/{$listUUID}/{$rawName}"); - - // Step 2: add with generic name + spec - $addBody = http_build_query([ - 'uuid' => $listUUID, - 'purchase' => $shoppingName, - 'specification' => $newSpec, - ]); - $result = bringRequest('PUT', "https://api.getbring.com/rest/v2/bringlists/{$listUUID}", $addBody); - if ($result !== false) { - $migrated++; - } else { - $errors++; - } - } - - echo json_encode(['success' => true, 'migrated' => $migrated, 'skipped' => $skipped, 'errors' => $errors]); + echo json_encode(array_merge(['success' => true], $result)); } function invalidateSmartShoppingCache(): void { diff --git a/index.html b/index.html index 5ef7ae3..1ab8625 100644 --- a/index.html +++ b/index.html @@ -735,12 +735,6 @@ -
- -

Sostituisce i nomi specifici con quelli generici (es. "Mortadella IGP" → "Affettato") negli item già presenti in Bring!.

- - -