diff --git a/.github/workflows/baseline.xml b/.github/workflows/baseline.xml index 92cbeb4..73bd3f1 100644 --- a/.github/workflows/baseline.xml +++ b/.github/workflows/baseline.xml @@ -141,32 +141,15 @@ $value $value - + DEFAULT_USE_REDIS - LOOKUP_ID_ALBERTHEIJN - LOOKUP_ID_FEDERATION - LOOKUP_ID_JUMBO - LOOKUP_ID_OPENFOODFACTS - LOOKUP_ID_OPENGTINDB - LOOKUP_ID_PLUS - LOOKUP_ID_UPCDATABASE - LOOKUP_ID_UPCDB $config["LOOKUP_ORDER"] - - LOOKUP_ID_ALBERTHEIJN - LOOKUP_ID_FEDERATION - LOOKUP_ID_JUMBO - LOOKUP_ID_OPENFOODFACTS - LOOKUP_ID_OPENGTINDB - LOOKUP_ID_PLUS - LOOKUP_ID_UPCDATABASE - LOOKUP_ID_UPCDB - + diff --git a/config-dist.php b/config-dist.php index a766b53..9c67412 100644 --- a/config-dist.php +++ b/config-dist.php @@ -113,6 +113,20 @@ // "LOOKUP_UPC_DATABASE_KEY" => null ); +// List of available lookup providers +// Format: "ID" => ["class" => "ClassName", "file" => "filename.php"] +const LOOKUP_PROVIDERS = array( + "1" => ["class" => "ProviderOpenFoodFacts", "file" => "ProviderOpenFoodFacts.php"], + "2" => ["class" => "ProviderUpcDb", "file" => "ProviderUpcDb.php"], + "3" => ["class" => "ProviderUpcDatabase", "file" => "ProviderUpcDatabase.php"], + "4" => ["class" => "ProviderAlbertHeijn", "file" => "ProviderAlbertHeijn.php"], + "5" => ["class" => "ProviderJumbo", "file" => "ProviderJumbo.php"], + "6" => ["class" => "ProviderOpengtindb", "file" => "ProviderOpengtindb.php"], + "7" => ["class" => "ProviderFederation", "file" => "ProviderFederation.php"], + "8" => ["class" => "ProviderPlusSupermarkt", "file" => "ProviderPlusSupermarkt.php"], + "9" => ["class" => "ProviderDiscogs", "file" => "ProviderDiscogs.php"] +); + // Currently not in use const IS_DOCKER = false; diff --git a/incl/db.inc.php b/incl/db.inc.php index c8500cb..8b41984 100755 --- a/incl/db.inc.php +++ b/incl/db.inc.php @@ -44,16 +44,6 @@ const SECTION_LOGS = "log"; -const LOOKUP_ID_OPENFOODFACTS = "1"; -const LOOKUP_ID_UPCDB = "2"; -const LOOKUP_ID_UPCDATABASE = "3"; -const LOOKUP_ID_ALBERTHEIJN = "4"; -const LOOKUP_ID_JUMBO = "5"; -const LOOKUP_ID_OPENGTINDB = "6"; -const LOOKUP_ID_FEDERATION = "7"; -const LOOKUP_ID_PLUS = "8"; -const LOOKUP_ID_DISCOGS = "9"; - /** * Dockerfile changes this to "1", so that the default is true * For non-docker this should be false ("0"). @@ -119,15 +109,7 @@ class DatabaseConnection { "BBUDDY_SERVER_ENABLED" => "0", "BBUDDY_SERVER_POPUPSHOWN" => "0", "BBUDDY_SERVER_NEXTSYNC" => "0", - "LOOKUP_ORDER" => LOOKUP_ID_OPENFOODFACTS . "," . - LOOKUP_ID_UPCDB . "," . - LOOKUP_ID_UPCDATABASE . "," . - LOOKUP_ID_ALBERTHEIJN . "," . - LOOKUP_ID_PLUS . "," . - LOOKUP_ID_JUMBO . "," . - LOOKUP_ID_OPENGTINDB . "," . - LOOKUP_ID_DISCOGS . "," . - LOOKUP_ID_FEDERATION); + "LOOKUP_ORDER" => "1,2,3,4,8,5,6,9,7"); const DB_INT_VALUES = array("REVERT_TIME"); diff --git a/incl/lookupProviders/BarcodeLookup.class.php b/incl/lookupProviders/BarcodeLookup.class.php index 3a61c11..7265457 100644 --- a/incl/lookupProviders/BarcodeLookup.class.php +++ b/incl/lookupProviders/BarcodeLookup.class.php @@ -23,18 +23,6 @@ class BarcodeLookup { private const USE_DEBUG_PROVIDER = false; - private static $providers = array( - LOOKUP_ID_OPENFOODFACTS => "ProviderOpenFoodFacts", - LOOKUP_ID_UPCDB => "ProviderUpcDb", - LOOKUP_ID_UPCDATABASE => "ProviderUpcDatabase", - LOOKUP_ID_ALBERTHEIJN => "ProviderAlbertHeijn", - LOOKUP_ID_PLUS => "ProviderPlusSupermarkt", - LOOKUP_ID_JUMBO => "ProviderJumbo", - LOOKUP_ID_OPENGTINDB => "ProviderOpengtindb", - LOOKUP_ID_DISCOGS => "ProviderDiscogs", - LOOKUP_ID_FEDERATION => "ProviderFederation" - ); - /** * Look up a barcode using providers * @param string $barcode Input barcode @@ -46,11 +34,52 @@ public static function lookUp(string $barcode): ?array { } $config = BBConfig::getInstance(); $orderAsArray = explode(",", $config["LOOKUP_ORDER"]); + $providers = self::getProviders(); + foreach ($orderAsArray as $orderId) { - $result = (new self::$providers[$orderId]())->lookupBarcode($barcode); - if ($result != null) - return $result; + if (isset($providers[$orderId])) { + $result = $providers[$orderId]->lookupBarcode($barcode); + if ($result != null) + return $result; + } } return null; } + + /** + * @return LookupProvider[] + */ + public static function getProviders(): array { + $providers = []; + if (!defined('LOOKUP_PROVIDERS')) { + return []; + } + + foreach (LOOKUP_PROVIDERS as $id => $providerConfig) { + $className = $providerConfig['class']; + $fileName = $providerConfig['file']; + $filePath = __DIR__ . "/" . $fileName; + + if (file_exists($filePath)) { + require_once $filePath; + if (class_exists($className)) { + $provider = new $className(); + if ($provider instanceof LookupProvider) { + $provider->setId((string)$id); + $providers[$id] = $provider; + } + } + } + } + return $providers; + } + + /** + * @param string $id + * @return LookupProvider|null + */ + public static function getProvider(string $id): ?LookupProvider { + $providers = self::getProviders(); + return $providers[$id] ?? null; + } } diff --git a/incl/lookupProviders/LookupProvider.class.php b/incl/lookupProviders/LookupProvider.class.php index ffb21cd..949ff85 100644 --- a/incl/lookupProviders/LookupProvider.class.php +++ b/incl/lookupProviders/LookupProvider.class.php @@ -15,17 +15,6 @@ */ -require_once __DIR__ . "/ProviderOpenFoodFacts.php"; -require_once __DIR__ . "/ProviderUpcDb.php"; -require_once __DIR__ . "/ProviderJumbo.php"; -require_once __DIR__ . "/ProviderUpcDatabase.php"; -require_once __DIR__ . "/ProviderDebug.php"; -require_once __DIR__ . "/ProviderAlbertHeijn.php"; -require_once __DIR__ . "/ProviderPlusSupermarkt.php"; -require_once __DIR__ . "/ProviderOpengtindb.php"; -require_once __DIR__ . "/ProviderDiscogs.php"; -require_once __DIR__ . "/ProviderFederation.php"; - abstract class LookupProviderType { const OpenFoodFacts = 0; @@ -39,26 +28,17 @@ abstract class LookupProviderType const Discogs = 8; } -class LookupProvider { +abstract class LookupProvider { protected $useGenericName; protected $apiKey; - protected $providerName; protected $ignoredResultCodes = null; - protected $providerConfigKey = null; + protected $id; function __construct(string $apiKey = null) { - $this->useGenericName = BBConfig::getInstance()["USE_GENERIC_NAME"]; - $this->apiKey = $apiKey; - } - - /** - * @return bool - */ - protected function isProviderEnabled(): bool { - if ($this->providerConfigKey == null) - throw new Exception('providerConfigKey needs to be overriden!'); - return BBConfig::getInstance()[$this->providerConfigKey] == "1"; + $this->apiKey = $apiKey; + $this->useGenericName = (BBConfig::getInstance()["USE_GENERIC_NAME"] == "1"); + $this->ignoredResultCodes = array(); } /** @@ -71,6 +51,77 @@ public function lookupBarcode(string $barcode): ?array { throw new Exception('lookupBarcode needs to be overriden!'); } + /** + * Sets the unique ID of the provider + * @param string $id + * @return void + */ + public function setId(string $id): void { + $this->id = $id; + } + + /** + * Returns the unique ID of the provider + * @return string + */ + public function getId(): string { + return $this->id; + } + + /** + * Returns the human readable name of the provider + * @return string + */ + abstract public function getName(): string; + + /** + * Returns the description shown below the provider name in settings + * @return string + */ + abstract public function getDescription(): string; + + /** + * Returns the configuration key for enabling/disabling the provider + * @return string + */ + abstract public function getConfigKey(): string; + + /** + * Generates the configuration UI for this provider (excluding enablement checkbox) + * Override this method if your provider needs custom configuration fields + * @param UiEditor $html + * @return string + */ + public function getConfigHtml(UiEditor $html): string { + return ""; + } + + /** + * Returns true if the provider is enabled + * @return bool + */ + public function isEnabled(): bool { + return BBConfig::getInstance()[$this->getConfigKey()] == "1"; + } + + /** + * Returns the ID of the main configuration field (e.g. API key) to be toggled + * @return string|null + */ + public function getConfigFieldId(): ?string { + return null; + } + + /** + * Saves the settings from the POST data + * Override this method if your provider needs custom save logic + * @param array $postData + * @return void + */ + public function saveSettings(array $postData): void { + // Default implementation does nothing - generic saver handles standard fields + } + /** * Returns the generic or product name, depending what user set in config or if * a product / generic name is available @@ -120,31 +171,31 @@ protected function execute(string $url, string $method = METHOD_GET, array $form $class = get_class($e); switch ($class) { case 'InvalidServerResponseException': - API::logError("Could not connect to " . $this->providerName . ".", false); + API::logError("Could not connect to " . $this->getName() . ".", false); return null; case 'UnauthorizedException': - API::logError("Could not connect to " . $this->providerName . " - unauthorized"); + API::logError("Could not connect to " . $this->getName() . " - unauthorized"); return null; case 'InvalidJsonResponseException': - API::logError("Error parsing " . $this->providerName . " response: " . $e->getMessage(), false); + API::logError("Error parsing " . $this->getName() . " response: " . $e->getMessage(), false); return null; case 'InvalidSSLException': - API::logError("Could not connect to " . $this->providerName . " - invalid SSL certificate"); + API::logError("Could not connect to " . $this->getName() . " - invalid SSL certificate"); return null; case 'InvalidParameterException': - API::logError("Internal error: Invalid parameter passed to " . $this->providerName . "."); + API::logError("Internal error: Invalid parameter passed to " . $this->getName() . "."); return null; case 'NotFoundException': - API::logError("Server " . $this->providerName . " reported path not found."); + API::logError("Server " . $this->getName() . " reported path not found."); return null; case 'LimitExceededException': - API::logError("Connection limits exceeded for " . $this->providerName . "."); + API::logError("Connection limits exceeded for " . $this->getName() . "."); return null; case 'InternalServerErrorException': - API::logError($this->providerName . " reported internal error."); + API::logError($this->getName() . " reported internal error."); return null; default: - API::logError("Unknown error with " . $this->providerName . ": " . $e->getMessage()); + API::logError("Unknown error with " . $this->getName() . ": " . $e->getMessage()); return null; } } diff --git a/incl/lookupProviders/ProviderAlbertHeijn.php b/incl/lookupProviders/ProviderAlbertHeijn.php index 2c5c08b..03cc4ba 100644 --- a/incl/lookupProviders/ProviderAlbertHeijn.php +++ b/incl/lookupProviders/ProviderAlbertHeijn.php @@ -24,19 +24,34 @@ class ProviderAlbertHeijn extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Albert Heijn"; - $this->providerConfigKey = "LOOKUP_USE_AH"; $this->ignoredResultCodes = array("404"); $this->db = DatabaseConnection::getInstance(); } + + public function getName(): string { + return "Albert Heijn"; + } + + public function getDescription(): string { + return "Uses Albert Heijn API"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_AH"; + } + + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; if (strlen($barcode) >= 20) return null; diff --git a/incl/lookupProviders/ProviderDebug.php b/incl/lookupProviders/ProviderDebug.php index 0531e3c..d2dc59c 100644 --- a/incl/lookupProviders/ProviderDebug.php +++ b/incl/lookupProviders/ProviderDebug.php @@ -23,10 +23,25 @@ class ProviderDebug extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Debug Lookup"; - $this->providerConfigKey = "USE_DEBUG_LOOKUP"; } + + public function getName(): string { + return "Debug Provider"; + } + + public function getDescription(): string { + return "Debug lookup provider"; + } + + public function getConfigKey(): string { + return "USE_DEBUG_LOOKUP"; + } + + + + + public function lookupBarcode(string $barcode): ?array { return self::createReturnArray(self::RETURN_STRING); } diff --git a/incl/lookupProviders/ProviderDiscogs.php b/incl/lookupProviders/ProviderDiscogs.php index 8cc24e5..18c34a4 100644 --- a/incl/lookupProviders/ProviderDiscogs.php +++ b/incl/lookupProviders/ProviderDiscogs.php @@ -24,11 +24,44 @@ class ProviderDiscogs extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Discogs DB"; - $this->providerConfigKey = "LOOKUP_USE_DISCOGS"; $this->ignoredResultCodes = array(400, 404); } + + public function getName(): string { + return "Discogs Database"; + } + + public function getDescription(): string { + return "Uses Discogs.com"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_DISCOGS"; + } + + public function getConfigFieldId(): ?string { + return 'LOOKUP_DISCOGS_TOKEN'; + } + + public function getConfigHtml(UiEditor $html): string { + $config = BBConfig::getInstance(); + /** @var string $output */ + $output = (new EditFieldBuilder( + 'LOOKUP_DISCOGS_TOKEN', + 'discogs.com Access Token', + $config['LOOKUP_DISCOGS_TOKEN'], + $html) + )->disabled(!$this->isEnabled()) + ->required($this->isEnabled()) + ->pattern('[A-Za-z0-9]{40}') + ->generate(true); + + return $output; + } + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup @@ -37,7 +70,7 @@ function __construct(string $apiKey = null) { public function lookupBarcode(string $barcode): ?array { $discogs_token = BBConfig::getInstance()['LOOKUP_DISCOGS_TOKEN']; - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; $url = "https://api.discogs.com/database/search?q=". $barcode . "&token=" . $discogs_token; diff --git a/incl/lookupProviders/ProviderFederation.php b/incl/lookupProviders/ProviderFederation.php index 0053168..3633c3f 100644 --- a/incl/lookupProviders/ProviderFederation.php +++ b/incl/lookupProviders/ProviderFederation.php @@ -22,18 +22,36 @@ class ProviderFederation extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Barcode Buddy Cloud"; - $this->providerConfigKey = "LOOKUP_USE_BBUDDY_SERVER"; $this->ignoredResultCodes = array(529); } + + public function getName(): string { + return "Barcode Buddy Federation"; + } + + public function getDescription(): string { + $config = BBConfig::getInstance(); + if (!$config["BBUDDY_SERVER_ENABLED"]) + return "Enable Federation for this feature"; + return "Uses " . BarcodeFederation::HOST_READABLE; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_BBUDDY_SERVER"; + } + + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; $url = BarcodeFederation::HOST . "/get"; diff --git a/incl/lookupProviders/ProviderJumbo.php b/incl/lookupProviders/ProviderJumbo.php index 2d6a11a..6fd7742 100644 --- a/incl/lookupProviders/ProviderJumbo.php +++ b/incl/lookupProviders/ProviderJumbo.php @@ -21,18 +21,33 @@ class ProviderJumbo extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Jumbo Group"; - $this->providerConfigKey = "LOOKUP_USE_JUMBO"; $this->ignoredResultCodes = array(); } + + public function getName(): string { + return "Jumbo"; + } + + public function getDescription(): string { + return "Uses Jumbo API"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_JUMBO"; + } + + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; $userAgent = "Mozilla/5.0 (Linux; Android 11; SM-N976N Build/RP1A.200720.012; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.163 Whale/1.0.0.0 Crosswalk/25.80.14.24 Mobile Safari/537.36 NAVER(inapp; search; 598; 11.0.6)"; diff --git a/incl/lookupProviders/ProviderOpenFoodFacts.php b/incl/lookupProviders/ProviderOpenFoodFacts.php index c395aaa..0fac5da 100644 --- a/incl/lookupProviders/ProviderOpenFoodFacts.php +++ b/incl/lookupProviders/ProviderOpenFoodFacts.php @@ -23,17 +23,31 @@ class ProviderOpenFoodFacts extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "OpenFoodFacts"; - $this->providerConfigKey = "LOOKUP_USE_OFF"; } + + public function getName(): string { + return "Open Food Facts"; + } + + public function getDescription(): string { + return "Uses OpenFoodFacts.org"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_OFF"; + } + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; global $CONFIG; diff --git a/incl/lookupProviders/ProviderOpengtindb.php b/incl/lookupProviders/ProviderOpengtindb.php index 032f988..e27cecb 100644 --- a/incl/lookupProviders/ProviderOpengtindb.php +++ b/incl/lookupProviders/ProviderOpengtindb.php @@ -22,11 +22,44 @@ class ProviderOpengtindb extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "Open EAN / GTIN Database"; - $this->providerConfigKey = "LOOKUP_USE_OPEN_GTIN_DATABASE"; $this->ignoredResultCodes = array(); } + + public function getName(): string { + return "Open EAN / GTIN Database"; + } + + public function getDescription(): string { + return "Uses OpenGtinDb.org"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_OPEN_GTIN_DATABASE"; + } + + public function getConfigFieldId(): ?string { + return 'LOOKUP_OPENGTIN_KEY'; + } + + public function getConfigHtml(UiEditor $html): string { + $config = BBConfig::getInstance(); + /** @var string $output */ + $output = (new EditFieldBuilder( + 'LOOKUP_OPENGTIN_KEY', + 'OpenGtinDb.org API Key', + $config['LOOKUP_OPENGTIN_KEY'], + $html) + )->disabled(!$this->isEnabled()) + ->required($this->isEnabled()) + ->pattern('[^%]{3,}') + ->generate(true); + + return $output; + } + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup @@ -34,7 +67,7 @@ function __construct(string $apiKey = null) { */ public function lookupBarcode(string $barcode): ?array { $opoengtinKey = BBConfig::getInstance()['LOOKUP_OPENGTIN_KEY']; - if (!$this->isProviderEnabled() || !$opoengtinKey) + if (!$this->isEnabled() || !$opoengtinKey) return null; $paddedBarcode = str_pad($barcode, 13, "0", STR_PAD_LEFT); diff --git a/incl/lookupProviders/ProviderPlusSupermarkt.php b/incl/lookupProviders/ProviderPlusSupermarkt.php index 2e0bda3..9b766b6 100644 --- a/incl/lookupProviders/ProviderPlusSupermarkt.php +++ b/incl/lookupProviders/ProviderPlusSupermarkt.php @@ -21,18 +21,33 @@ class ProviderPlusSupermarkt extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = 'Plus Supermarkt'; - $this->providerConfigKey = 'LOOKUP_USE_PLUS'; $this->ignoredResultCodes = array('404'); } + + public function getName(): string { + return "Plus Supermarkt"; + } + + public function getDescription(): string { + return "Uses Plus Supermarkt API"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_PLUS"; + } + + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) { + if (!$this->isEnabled()) { return null; } diff --git a/incl/lookupProviders/ProviderUpcDatabase.php b/incl/lookupProviders/ProviderUpcDatabase.php index 76a0f37..854d66b 100644 --- a/incl/lookupProviders/ProviderUpcDatabase.php +++ b/incl/lookupProviders/ProviderUpcDatabase.php @@ -22,11 +22,44 @@ class ProviderUpcDatabase extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "UPC Database"; - $this->providerConfigKey = "LOOKUP_USE_UPC_DATABASE"; $this->ignoredResultCodes = array(); } + + public function getName(): string { + return "UPC Database"; + } + + public function getDescription(): string { + return "Uses UPCDatabase.org"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_UPC_DATABASE"; + } + + public function getConfigFieldId(): ?string { + return 'LOOKUP_UPC_DATABASE_KEY'; + } + + public function getConfigHtml(UiEditor $html): string { + $config = BBConfig::getInstance(); + /** @var string $output */ + $output = (new EditFieldBuilder( + 'LOOKUP_UPC_DATABASE_KEY', + 'UPCDatabase.org API Key', + $config['LOOKUP_UPC_DATABASE_KEY'], + $html) + )->disabled(!$this->isEnabled()) + ->required($this->isEnabled()) + ->pattern('[A-Za-z0-9]{32}') + ->generate(true); + + return $output; + } + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup @@ -34,7 +67,7 @@ function __construct(string $apiKey = null) { */ public function lookupBarcode(string $barcode): ?array { $upcdb_key = BBConfig::getInstance()['LOOKUP_UPC_DATABASE_KEY']; - if (!$this->isProviderEnabled() || !$upcdb_key) + if (!$this->isEnabled() || !$upcdb_key) return null; $paddedBarcode = str_pad($barcode, 13, "0", STR_PAD_LEFT); diff --git a/incl/lookupProviders/ProviderUpcDb.php b/incl/lookupProviders/ProviderUpcDb.php index d91a3bd..b99baa0 100644 --- a/incl/lookupProviders/ProviderUpcDb.php +++ b/incl/lookupProviders/ProviderUpcDb.php @@ -22,18 +22,33 @@ class ProviderUpcDb extends LookupProvider { function __construct(string $apiKey = null) { parent::__construct($apiKey); - $this->providerName = "UPC Item DB"; - $this->providerConfigKey = "LOOKUP_USE_UPC"; $this->ignoredResultCodes = array(400, 404); } + + public function getName(): string { + return "UPC Item DB"; + } + + public function getDescription(): string { + return "Uses UPCitemDB.com"; + } + + public function getConfigKey(): string { + return "LOOKUP_USE_UPC"; + } + + + + + /** * Looks up a barcode * @param string $barcode The barcode to lookup * @return array|null Name of product, null if none found */ public function lookupBarcode(string $barcode): ?array { - if (!$this->isProviderEnabled()) + if (!$this->isEnabled()) return null; $url = "https://api.upcitemdb.com/prod/trial/lookup?upc=" . $barcode; diff --git a/menu/federation.php b/menu/federation.php index 10ae94f..8c01ac9 100644 --- a/menu/federation.php +++ b/menu/federation.php @@ -36,6 +36,7 @@ $webUi = new WebUiGenerator(MENU_GENERIC); $webUi->addHeader(); +/** @var string $loadingSpinner */ $loadingSpinner = (new UiEditor())->addLoadingSpinner("loading",true); $webUi->addCard('Barcode Buddy Federation '.$loadingSpinner.'', getHtmlFederation()); $webUi->addCard('Info ', getHtmlFederationInfo()); diff --git a/menu/settings.php b/menu/settings.php index 501e443..3910a32 100755 --- a/menu/settings.php +++ b/menu/settings.php @@ -71,6 +71,12 @@ function saveSettings(): void { } } } + + // Save provider settings + $providers = BarcodeLookup::getProviders(); + foreach ($providers as $provider) { + $provider->saveSettings($_POST); + } } @@ -142,48 +148,92 @@ function getHtmlSettingsBarcodeLookup(): string { $html->addHtml("Use Drag&Drop for changing lookup order"); $html->addHtml('
    '); - $providerList = getProviderListItems($html); + $providers = BarcodeLookup::getProviders(); + $providerList = []; + + // Generic JS handler for toggling config fields + $html->addScript(' + function toggleConfigField(checkbox, fieldId) { + var field = document.getElementById(fieldId); + if (!field) return; + + if (checkbox.checked) { + field.disabled = false; + field.parentElement.classList.remove("is-disabled"); + field.required = true; + } else { + field.disabled = true; + field.parentElement.classList.add("is-disabled"); + field.required = false; + // Clear validation error if present + field.parentElement.classList.remove("is-invalid"); + } + } + '); + + foreach ($providers as $provider) { + $configFieldId = $provider->getConfigFieldId(); + + if ($configFieldId) { + // Use CheckBoxBuilder for providers with config to attach JS handler + $checkbox = (new CheckBoxBuilder( + $provider->getConfigKey(), + $provider->getName(), + (string)$provider->isEnabled(), + $html + ))->onCheckChanged("toggleConfigField(this, '$configFieldId')") + ->generate(true); + } else { + // Use simple addCheckbox for providers without config (matches original convention) + $checkbox = $html->addCheckbox( + $provider->getConfigKey(), + $provider->getName(), + (string)$provider->isEnabled(), + false, + false, + true + ); + } + + $configHtml = $provider->getConfigHtml($html); + $description = $provider->getDescription(); + + // Combine description and config HTML + $body = $description; + if (!empty($configHtml)) { + $body .= "

    " . $configHtml; + } + + // Manually construct list item to allow for auto height and proper vertical stacking + /** @var string $checkbox */ + $providerList["id" . $provider->getId()] = " +
  • getId() . "\" class=\"mdl-list__item\" style=\"height:auto; min-height: auto; padding: 16px; display: block;\" data-value=\"" . $provider->getId() . "\"> +
    + " . $checkbox . " +
    +
    + " . $description . " + " . (!empty($configHtml) ? "
    " . $configHtml . "
    " : "") . " +
    +
  • "; + } + $orderAsArray = explode(",", $config["LOOKUP_ORDER"]); foreach ($orderAsArray as $orderId) { - $html->addHtml($providerList["id" . $orderId]); + if (isset($providerList["id" . $orderId])) { + $html->addHtml($providerList["id" . $orderId]); + unset($providerList["id" . $orderId]); + } } + // Add any remaining providers that might not be in the order list yet + foreach ($providerList as $item) { + $html->addHtml($item); + } $html->addHtml('
'); $html->addLineBreak(); - $html->addHtml((new EditFieldBuilder( - 'LOOKUP_UPC_DATABASE_KEY', - 'UPCDatabase.org API Key', - $config["LOOKUP_UPC_DATABASE_KEY"], - $html)) - ->required($config["LOOKUP_USE_UPC_DATABASE"]) - ->pattern('[A-Za-z0-9]{32}') - ->disabled(!$config["LOOKUP_USE_UPC_DATABASE"]) - ->generate(true) - ); - $html->addLineBreak(); - $html->addHtml((new EditFieldBuilder( - 'LOOKUP_OPENGTIN_KEY', - 'OpenGtinDb.org API Key', - $config["LOOKUP_OPENGTIN_KEY"], - $html)) - ->required($config["LOOKUP_USE_OPEN_GTIN_DATABASE"]) - ->pattern('[^%]{3,}') - ->disabled(!$config["LOOKUP_USE_OPEN_GTIN_DATABASE"]) - ->generate(true) - ); - - $html->addLineBreak(); - $html->addHtml((new EditFieldBuilder( - 'LOOKUP_DISCOGS_TOKEN', - 'discogs.com Access Token', - $config["LOOKUP_DISCOGS_TOKEN"], - $html)) - ->required($config["LOOKUP_USE_DISCOGS"]) - ->pattern('[A-Za-z0-9]{40}') - ->disabled(!$config["LOOKUP_USE_DISCOGS"]) - ->generate(true) - ); + $html->addHiddenField("LOOKUP_ORDER", $config["LOOKUP_ORDER"]); $html->addScript("var elements = document.getElementById('providers'); @@ -196,67 +246,6 @@ function getHtmlSettingsBarcodeLookup(): string { return $html->getHtml(); } -function generateApiKeyChangeScript(string $functionName, string $keyId): string { - return "function " . $functionName . "(element) { - apiEditField = document.getElementById('" . $keyId . "'); - if (!apiEditField) { - console.warn('Unable to find element " . $keyId . "'); - } else { - apiEditField.required = element.checked; - if (element.checked) { - apiEditField.parentNode.MaterialTextfield.enable(); - } else { - apiEditField.parentNode.MaterialTextfield.disable(); - } - } - }"; -} - -function getProviderListItems(UiEditor $html): array { - $config = BBConfig::getInstance(); - $result = array(); - $result["id" . LOOKUP_ID_OPENFOODFACTS] = $html->addListItem($html->addCheckbox('LOOKUP_USE_OFF', 'Open Food Facts', $config["LOOKUP_USE_OFF"], false, false, true), "Uses OpenFoodFacts.org", LOOKUP_ID_OPENFOODFACTS, true); - $result["id" . LOOKUP_ID_UPCDB] = $html->addListItem($html->addCheckbox('LOOKUP_USE_UPC', 'UPC Item DB', $config["LOOKUP_USE_UPC"], false, false, true), "Uses UPCitemDB.com", LOOKUP_ID_UPCDB, true); - $result["id" . LOOKUP_ID_ALBERTHEIJN] = $html->addListItem($html->addCheckbox('LOOKUP_USE_AH', 'Albert Heijn', $config["LOOKUP_USE_AH"], false, false, true), "Uses AH.nl", LOOKUP_ID_ALBERTHEIJN, true); - $result["id" . LOOKUP_ID_PLUS] = $html->addListItem($html->addCheckbox('LOOKUP_USE_PLUS', 'Plus Supermarkt', $config["LOOKUP_USE_PLUS"], false, false, true), "Uses PLUS.nl", LOOKUP_ID_PLUS, true); - $result["id" . LOOKUP_ID_JUMBO] = $html->addListItem($html->addCheckbox('LOOKUP_USE_JUMBO', 'Jumbo', $config["LOOKUP_USE_JUMBO"], false, false, true), "Uses Jumbo.com (slow)", LOOKUP_ID_JUMBO, true); - $result["id" . LOOKUP_ID_UPCDATABASE] = $html->addListItem((new CheckBoxBuilder( - "LOOKUP_USE_UPC_DATABASE", - "UPC Database", - $config["LOOKUP_USE_UPC_DATABASE"], - $html) - )->onCheckChanged( - "handleUPCDBChange(this)", - generateApiKeyChangeScript("handleUPCDBChange", "LOOKUP_UPC_DATABASE_KEY")) - ->generate(true), "Uses UPCDatabase.org", LOOKUP_ID_UPCDATABASE, true); - - $result["id" . LOOKUP_ID_OPENGTINDB] = $html->addListItem((new CheckBoxBuilder( - "LOOKUP_USE_OPEN_GTIN_DATABASE", - "Open EAN / GTIN Database", - $config["LOOKUP_USE_OPEN_GTIN_DATABASE"], - $html) - )->onCheckChanged( - "handleOpenGtinChange(this)", - generateApiKeyChangeScript("handleOpenGtinChange", "LOOKUP_OPENGTIN_KEY")) - ->generate(true), "Uses OpenGtinDb.org", LOOKUP_ID_OPENGTINDB, true); - - $result["id" . LOOKUP_ID_DISCOGS] = $html->addListItem((new CheckBoxBuilder( - "LOOKUP_USE_DISCOGS", - "Discogs Database", - $config["LOOKUP_USE_DISCOGS"], - $html) - )->onCheckChanged( - "handleDiscogsChange(this)", - generateApiKeyChangeScript("handleDiscogsChange", "LOOKUP_DISCOGS_TOKEN")) - ->generate(true), "Uses Discogs.com", LOOKUP_ID_DISCOGS, true); - - $bbServerSubtitle = "Uses " . BarcodeFederation::HOST_READABLE; - if (!$config["BBUDDY_SERVER_ENABLED"]) - $bbServerSubtitle = "Enable Federation for this feature"; - $result["id" . LOOKUP_ID_FEDERATION] = $html->addListItem($html->addCheckbox('LOOKUP_USE_BBUDDY_SERVER', 'Barcode Buddy Federation', $config["LOOKUP_USE_BBUDDY_SERVER"], !$config["BBUDDY_SERVER_ENABLED"], false, true), $bbServerSubtitle, LOOKUP_ID_FEDERATION, true); - return $result; -} - /** * @return string