diff --git a/controllers/BaseController.php b/controllers/BaseController.php index d948df20..8193624f 100644 --- a/controllers/BaseController.php +++ b/controllers/BaseController.php @@ -18,6 +18,7 @@ use Grocy\Services\StockService; use Grocy\Services\TasksService; use Grocy\Services\UserfieldsService; use Grocy\Services\UsersService; +use Grocy\Services\WebhookService; use DI\Container; class BaseController @@ -116,6 +117,11 @@ class BaseController return UsersService::getInstance(); } + protected function getWebhookService() + { + return WebhookService::getInstance(); + } + protected function render($response, $viewName, $data = []) { $container = $this->AppContainer; diff --git a/controllers/BatteriesApiController.php b/controllers/BatteriesApiController.php index b5cd7430..6d71df29 100644 --- a/controllers/BatteriesApiController.php +++ b/controllers/BatteriesApiController.php @@ -3,8 +3,8 @@ namespace Grocy\Controllers; use Grocy\Controllers\Users\User; -use Grocy\Helpers\WebhookRunner; use Grocy\Helpers\Grocycode; +use Grocy\Services\WebhookService; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -71,15 +71,12 @@ class BatteriesApiController extends BaseApiController { $battery = $this->getDatabase()->batteries()->where('id', $args['batteryId'])->fetch(); - $webhookData = array_merge([ + $webhookData = [ 'battery' => $battery->name, 'grocycode' => (string)(new Grocycode(Grocycode::BATTERY, $args['batteryId'])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; - if (GROCY_LABEL_PRINTER_RUN_SERVER) - { - (new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); - } + $this->getWebhookService()->run(WebhookService::EVENT_BATTERY_PRINT_LABEL, $webhookData); return $this->ApiResponse($response, $webhookData); } diff --git a/controllers/ChoresApiController.php b/controllers/ChoresApiController.php index e8a6d2f7..82623373 100644 --- a/controllers/ChoresApiController.php +++ b/controllers/ChoresApiController.php @@ -3,8 +3,8 @@ namespace Grocy\Controllers; use Grocy\Controllers\Users\User; -use Grocy\Helpers\WebhookRunner; use Grocy\Helpers\Grocycode; +use Grocy\Services\WebhookService; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -122,15 +122,12 @@ class ChoresApiController extends BaseApiController { $chore = $this->getDatabase()->chores()->where('id', $args['choreId'])->fetch(); - $webhookData = array_merge([ + $webhookData = [ 'chore' => $chore->name, 'grocycode' => (string)(new Grocycode(Grocycode::CHORE, $args['choreId'])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; - if (GROCY_LABEL_PRINTER_RUN_SERVER) - { - (new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); - } + $this->getWebhookService()->run(WebhookService::EVENT_CHORE_PRINT_LABEL, $webhookData); return $this->ApiResponse($response, $webhookData); } diff --git a/controllers/RecipesApiController.php b/controllers/RecipesApiController.php index 36e76020..aff5fdf5 100644 --- a/controllers/RecipesApiController.php +++ b/controllers/RecipesApiController.php @@ -3,8 +3,8 @@ namespace Grocy\Controllers; use Grocy\Controllers\Users\User; -use Grocy\Helpers\WebhookRunner; use Grocy\Helpers\Grocycode; +use Grocy\Services\WebhookService; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -87,15 +87,12 @@ class RecipesApiController extends BaseApiController { $recipe = $this->getDatabase()->recipes()->where('id', $args['recipeId'])->fetch(); - $webhookData = array_merge([ + $webhookData = [ 'recipe' => $recipe->name, 'grocycode' => (string)(new Grocycode(Grocycode::RECIPE, $args['recipeId'])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; - if (GROCY_LABEL_PRINTER_RUN_SERVER) - { - (new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); - } + $this->getWebhookService()->run(WebhookService::EVENT_RECIPE_PRINT_LABEL, $webhookData); return $this->ApiResponse($response, $webhookData); } diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index 27fd5b26..c52f6da2 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -4,7 +4,7 @@ namespace Grocy\Controllers; use Grocy\Controllers\Users\User; use Grocy\Services\StockService; -use Grocy\Helpers\WebhookRunner; +use Grocy\Services\WebhookService; use Grocy\Helpers\Grocycode; use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ServerRequestInterface as Request; @@ -674,15 +674,12 @@ class StockApiController extends BaseApiController { $product = $this->getDatabase()->products()->where('id', $args['productId'])->fetch(); - $webhookData = array_merge([ + $webhookData = [ 'product' => $product->name, 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $product->id)), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; - if (GROCY_LABEL_PRINTER_RUN_SERVER) - { - (new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); - } + $this->getWebhookService()->run(WebhookService::EVENT_PRODUCT_PRINT_LABEL, $webhookData); return $this->ApiResponse($response, $webhookData); } @@ -699,20 +696,17 @@ class StockApiController extends BaseApiController $stockEntry = $this->getDatabase()->stock()->where('id', $args['entryId'])->fetch(); $product = $this->getDatabase()->products()->where('id', $stockEntry->product_id)->fetch(); - $webhookData = array_merge([ + $webhookData = [ 'product' => $product->name, 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $stockEntry->product_id, [$stockEntry->stock_id])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) { $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $stockEntry->best_before_date; } - if (GROCY_LABEL_PRINTER_RUN_SERVER) - { - (new WebhookRunner())->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); - } + $this->getWebhookService()->run(WebhookService::EVENT_STOCK_ENTRY_PRINT_LABEL, $webhookData); return $this->ApiResponse($response, $webhookData); } diff --git a/helpers/WebhookRunner.php b/helpers/WebhookRunner.php deleted file mode 100644 index 150155a5..00000000 --- a/helpers/WebhookRunner.php +++ /dev/null @@ -1,48 +0,0 @@ -client = new Client(['timeout' => 2.0]); - } - - private $client; - - public function run($url, $args, $json = false) - { - $reqArgs = []; - if ($json) - { - $reqArgs = ['json' => $args]; - } - else - { - $reqArgs = ['form_params' => $args]; - } - try - { - file_put_contents('php://stderr', 'Running Webhook: ' . $url . "\n" . print_r($reqArgs, true)); - - $this->client->request('POST', $url, $reqArgs); - } - catch (RequestException $e) - { - file_put_contents('php://stderr', 'Webhook failed: ' . $url . "\n" . $e->getMessage()); - } - } - - public function runAll($urls, $args) - { - foreach ($urls as $url) - { - $this->run($url, $args); - } - } -} diff --git a/services/BaseService.php b/services/BaseService.php index 13825068..aafee1d8 100644 --- a/services/BaseService.php +++ b/services/BaseService.php @@ -76,4 +76,9 @@ class BaseService { return ApplicationService::getInstance(); } + + protected function getWebhookService() + { + return WebhookService::getInstance(); + } } diff --git a/services/StockService.php b/services/StockService.php index 3c60714b..28d31725 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -3,7 +3,7 @@ namespace Grocy\Services; use Grocy\Helpers\Grocycode; -use Grocy\Helpers\WebhookRunner; +use Grocy\Services\WebhookService; use GuzzleHttp\Client; class StockService extends BaseService @@ -220,21 +220,17 @@ class StockService extends BaseService ]); $stockRow->save(); - if (GROCY_FEATURE_FLAG_LABEL_PRINTER && GROCY_LABEL_PRINTER_RUN_SERVER) + $webhookData = [ + 'product' => $productDetails->product->name, + 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productId, [$stockId])), + ]; + + if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) { - $webhookData = array_merge([ - 'product' => $productDetails->product->name, - 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productId, [$stockId])), - ], GROCY_LABEL_PRINTER_PARAMS); - - if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) - { - $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $bestBeforeDate; - } - - $runner = new WebhookRunner(); - $runner->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); + $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $bestBeforeDate; } + + $this->getWebhookService()->run(WebhookService::EVENT_ADD_PRODUCT, $webhookData); } } else @@ -271,20 +267,19 @@ class StockService extends BaseService ]); $stockRow->save(); - if ($stockLabelType == 1 && GROCY_FEATURE_FLAG_LABEL_PRINTER && GROCY_LABEL_PRINTER_RUN_SERVER) + if ($stockLabelType == 1) { - $webhookData = array_merge([ + $webhookData = [ 'product' => $productDetails->product->name, 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productId, [$stockId])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) { $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $bestBeforeDate; } - $runner = new WebhookRunner(); - $runner->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); + $this->getWebhookService()->run(WebhookService::EVENT_ADD_PRODUCT, $webhookData); } } @@ -996,20 +991,19 @@ class StockService extends BaseService $newBestBeforeDate = $stockEntry->best_before_date; } - if (GROCY_FEATURE_FLAG_LABEL_PRINTER && GROCY_LABEL_PRINTER_RUN_SERVER && $productDetails->product->auto_reprint_stock_label == 1 && $newBestBeforeDate != $stockEntry->best_before_date) + if ($productDetails->product->auto_reprint_stock_label == 1 && $newBestBeforeDate != $stockEntry->best_before_date) { - $webhookData = array_merge([ + $webhookData = [ 'product' => $productDetails->product->name, 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productId, [$stockEntry->stock_id])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) { $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $newBestBeforeDate; } - $runner = new WebhookRunner(); - $runner->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); + $this->getWebhookService()->run(WebhookService::EVENT_OPEN_PRODUCT, $webhookData); } } @@ -1308,20 +1302,19 @@ class StockService extends BaseService $newBestBeforeDate = date('Y-m-d', strtotime('+' . $productDetails->product->default_best_before_days_after_thawing . ' days')); } - if (GROCY_FEATURE_FLAG_LABEL_PRINTER && GROCY_LABEL_PRINTER_RUN_SERVER && $productDetails->product->auto_reprint_stock_label == 1 && $stockEntry->best_before_date != $newBestBeforeDate) + if ($productDetails->product->auto_reprint_stock_label == 1 && $stockEntry->best_before_date != $newBestBeforeDate) { - $webhookData = array_merge([ + $webhookData = [ 'product' => $productDetails->product->name, 'grocycode' => (string)(new Grocycode(Grocycode::PRODUCT, $productId, [$stockEntry->stock_id])), - ], GROCY_LABEL_PRINTER_PARAMS); + ]; if (GROCY_FEATURE_FLAG_STOCK_BEST_BEFORE_DATE_TRACKING) { $webhookData['due_date'] = $this->getLocalizationService()->__t('DD') . ': ' . $newBestBeforeDate; } - $runner = new WebhookRunner(); - $runner->run(GROCY_LABEL_PRINTER_WEBHOOK, $webhookData, GROCY_LABEL_PRINTER_HOOK_JSON); + $this->getWebhookService()->run(WebhookService::EVENT_TRANSFER_PRODUCT, $webhookData); } } diff --git a/services/WebhookService.php b/services/WebhookService.php new file mode 100644 index 00000000..d0bc2520 --- /dev/null +++ b/services/WebhookService.php @@ -0,0 +1,113 @@ + GROCY_LABEL_PRINTER_WEBHOOK, + 'default_args' => GROCY_LABEL_PRINTER_PARAMS, + 'json' => GROCY_LABEL_PRINTER_HOOK_JSON, + 'include_events' => [ + WebhookService::EVENT_BATTERY_PRINT_LABEL, + WebhookService::EVENT_CHORE_PRINT_LABEL, + WebhookService::EVENT_RECIPE_PRINT_LABEL, + WebhookService::EVENT_PRODUCT_PRINT_LABEL, + WebhookService::EVENT_STOCK_ENTRY_PRINT_LABEL, + WebhookService::EVENT_ADD_PRODUCT, + WebhookService::EVENT_OPEN_PRODUCT, + WebhookService::EVENT_TRANSFER_PRODUCT, + ], + 'exclude_events' => [], + 'enabled' => GROCY_FEATURE_FLAG_LABEL_PRINTER && GROCY_LABEL_PRINTER_RUN_SERVER, + ], +]; + +class WebhookService extends BaseService +{ + const EVENT_BATTERY_PRINT_LABEL = 'battery_print_label'; + const EVENT_CHORE_PRINT_LABEL = 'chore_print_label'; + const EVENT_RECIPE_PRINT_LABEL = 'recipe_print_label'; + const EVENT_PRODUCT_PRINT_LABEL = 'product_print_label'; + const EVENT_STOCK_ENTRY_PRINT_LABEL = 'stock_entry_print_label'; + const EVENT_ADD_PRODUCT = 'add_product'; + const EVENT_OPEN_PRODUCT = 'open_product'; + const EVENT_TRANSFER_PRODUCT = 'transfer_product'; + + public function __construct() + { + $this->client = new Client(['timeout' => 2.0]); + } + + private $client; + + private function shouldFire($webhook, $event) + { + if (!$webhook['enabled']) + { + return false; + } + + $includeEvents = $webhook['include_events'] ?? []; + $excludeEvents = $webhook['exclude_events'] ?? []; + + // No restrictions + if (empty($includeEvents) && empty($excludeEvents)) + { + return true; + } + + // Only include events + if (!empty($includeEvents) && in_array($event, $includeEvents)) + { + return true; + } + + // Only exclude events + if (!empty($excludeEvents) && !in_array($event, $excludeEvents)) + { + return true; + } + + // No events match + return false; + } + + public function fire($event, $args) + { + foreach (WEBHOOKS as $webhook) + { + if ($this->shouldFire($webhook, $event)) + { + $webhookData = array_merge($webhook['default_args'], $args); + $this->run($webhook['url'], $webhookData, $webhook['json']); + } + } + } + + private function run($url, $args, $json = false) + { + $reqArgs = []; + if ($json) + { + $reqArgs = ['json' => $args]; + } + else + { + $reqArgs = ['form_params' => $args]; + } + try + { + file_put_contents('php://stderr', 'Running Webhook: ' . $url . "\n" . print_r($reqArgs, true)); + + $this->client->request('POST', $url, $reqArgs); + } + catch (RequestException $e) + { + file_put_contents('php://stderr', 'Webhook failed: ' . $url . "\n" . $e->getMessage()); + } + } +}