diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2f4c74a..d2bbf4f 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,8 @@ -### Fixes -- Many deprecation notices for PHP 8.2 about creation of dynamic properties (#201) \ No newline at end of file +### Issues Fixed + +Allow null `meta_description` on Product (Thanks @macbookandrew) + +### New Features + +Adds support for Webhooks API (#187) diff --git a/src/BigCommerce/Api/Webhooks/WebhookAdminApi.php b/src/BigCommerce/Api/Webhooks/WebhookAdminApi.php new file mode 100644 index 0000000..ae1d834 --- /dev/null +++ b/src/BigCommerce/Api/Webhooks/WebhookAdminApi.php @@ -0,0 +1,41 @@ + $isActive]; + return new AdminInfoResponse($this->getResource($filter)); + } + + /** + * Update email addresses that are sent notification emails when any domain associated with the API account + * is denylisted or when a webhook is deactivated. Supports upsert functionality in the case that no email + * address exists yet. + */ + public function upsertEmails(array $emails): void + { + $this->getClient()->getRestClient()->put( + $this->singleResourceUrl(), + [ + RequestOptions::JSON => ['emails' => $emails] + ] + ); + } +} diff --git a/src/BigCommerce/Api/Webhooks/WebhookEventsApi.php b/src/BigCommerce/Api/Webhooks/WebhookEventsApi.php new file mode 100644 index 0000000..73e6a3b --- /dev/null +++ b/src/BigCommerce/Api/Webhooks/WebhookEventsApi.php @@ -0,0 +1,27 @@ +getAllResources($filters, $page, $limit)); + } +} diff --git a/src/BigCommerce/Api/Webhooks/WebhooksApi.php b/src/BigCommerce/Api/Webhooks/WebhooksApi.php new file mode 100644 index 0000000..255b7b1 --- /dev/null +++ b/src/BigCommerce/Api/Webhooks/WebhooksApi.php @@ -0,0 +1,64 @@ +getResource()); + } + + /** + * Creates a webhook. Only one webhook at a time can be created. Custom headers can be added. + * Destination URL must be served on port 443 (custom ports are not currently supported). + */ + public function create(Webhook $webhook): WebhookResponse + { + return new WebhookResponse($this->createResource($webhook)); + } + + public function update(Webhook $webhook): WebhookResponse + { + return new WebhookResponse($this->updateResource($webhook)); + } + + protected function singleResourceEndpoint(): string + { + return self::WEBHOOK_ENDPOINT; + } + + protected function multipleResourcesEndpoint(): string + { + return self::WEBHOOKS_ENDPOINT; + } + + protected function resourceName(): string + { + return self::RESOURCE_NAME; + } + + public function getAll(array $filters = [], int $page = 1, int $limit = 250): WebhooksResponse + { + return new WebhooksResponse($this->getAllResources($filters, $page, $limit)); + } + + public function events(): WebhookEventsApi + { + return new WebhookEventsApi($this->getClient()); + } + + public function admin(): WebhookAdminApi + { + return new WebhookAdminApi($this->getClient()); + } +} diff --git a/src/BigCommerce/Client.php b/src/BigCommerce/Client.php index 2655714..16a5f1f 100644 --- a/src/BigCommerce/Client.php +++ b/src/BigCommerce/Client.php @@ -15,6 +15,7 @@ use BigCommerce\ApiV3\Api\Sites\SitesApi; use BigCommerce\ApiV3\Api\StoreLogs\StoreLogsApi; use BigCommerce\ApiV3\Api\Themes\ThemesApi; +use BigCommerce\ApiV3\Api\Webhooks\WebhooksApi; use BigCommerce\ApiV3\Api\Widgets\WidgetsApi; use BigCommerce\ApiV3\Api\CustomTemplateAssociations\CustomTemplateAssociationsApi; use BigCommerce\ApiV3\Api\Wishlists\WishlistsApi; @@ -223,6 +224,16 @@ public function storeLogs(): StoreLogsApi return new StoreLogsApi($this); } + public function webhook(int $id): WebhooksApi + { + return new WebhooksApi($this, $id); + } + + public function webhooks(): WebhooksApi + { + return new WebhooksApi($this); + } + protected function defaultBaseUrl(): string { return self::API_URI; diff --git a/src/BigCommerce/ResourceModels/Catalog/Product/Product.php b/src/BigCommerce/ResourceModels/Catalog/Product/Product.php index 6c98df7..d9bfa98 100644 --- a/src/BigCommerce/ResourceModels/Catalog/Product/Product.php +++ b/src/BigCommerce/ResourceModels/Catalog/Product/Product.php @@ -63,7 +63,7 @@ class Product extends ResourceModel public int $order_quantity_maximum; public string $page_title; public array $meta_keywords; - public string $meta_description; + public ?string $meta_description; public string $date_created; public string $date_modified; public int $view_count; diff --git a/src/BigCommerce/ResourceModels/ResourceModel.php b/src/BigCommerce/ResourceModels/ResourceModel.php index 12ab187..76a6ede 100644 --- a/src/BigCommerce/ResourceModels/ResourceModel.php +++ b/src/BigCommerce/ResourceModels/ResourceModel.php @@ -54,6 +54,15 @@ protected function buildPropertyObject(string $property, string $className): voi } } + protected function buildHashArray(string $property): void + { + if (!is_null($this->optionObject) && isset($this->optionObject->$property)) { + $this->$property = (array) $this->optionObject->$property; + + unset($this->optionObject->$property); + } + } + /** * Override this function to implement custom build functionality */ diff --git a/src/BigCommerce/ResourceModels/Webhook/BlockedDomain.php b/src/BigCommerce/ResourceModels/Webhook/BlockedDomain.php new file mode 100644 index 0000000..270a8e5 --- /dev/null +++ b/src/BigCommerce/ResourceModels/Webhook/BlockedDomain.php @@ -0,0 +1,22 @@ +adminInfo; + } + + protected function addData(stdClass $rawData): void + { + $this->adminInfo = new WebhookAdminInfo($rawData); + } +} diff --git a/src/BigCommerce/ResponseModels/Webhook/WebhookEventsResponse.php b/src/BigCommerce/ResponseModels/Webhook/WebhookEventsResponse.php new file mode 100644 index 0000000..23250f2 --- /dev/null +++ b/src/BigCommerce/ResponseModels/Webhook/WebhookEventsResponse.php @@ -0,0 +1,22 @@ +getData(); + } + + protected function resourceClass(): string + { + return WebhookEvent::class; + } +} diff --git a/src/BigCommerce/ResponseModels/Webhook/WebhookResponse.php b/src/BigCommerce/ResponseModels/Webhook/WebhookResponse.php new file mode 100644 index 0000000..64b790b --- /dev/null +++ b/src/BigCommerce/ResponseModels/Webhook/WebhookResponse.php @@ -0,0 +1,22 @@ +webhook; + } + + protected function addData(stdClass $rawData): void + { + $this->webhook = new Webhook($rawData); + } +} diff --git a/src/BigCommerce/ResponseModels/Webhook/WebhooksResponse.php b/src/BigCommerce/ResponseModels/Webhook/WebhooksResponse.php new file mode 100644 index 0000000..67d132a --- /dev/null +++ b/src/BigCommerce/ResponseModels/Webhook/WebhooksResponse.php @@ -0,0 +1,21 @@ +getData(); + } + protected function resourceClass(): string + { + return Webhook::class; + } +} diff --git a/tests/BigCommerce/Api/Webhooks/WebhookAdminApiTest.php b/tests/BigCommerce/Api/Webhooks/WebhookAdminApiTest.php new file mode 100644 index 0000000..6852171 --- /dev/null +++ b/tests/BigCommerce/Api/Webhooks/WebhookAdminApiTest.php @@ -0,0 +1,16 @@ +setReturnData('webhooks__admin__get.json'); + $info = $this->getApi()->webhooks()->admin()->get()->getAdminInfo(); + + $this->assertEquals('https://httpstat.us/200', $info->hooks_list[1]->destination); + } +} diff --git a/tests/BigCommerce/Api/Webhooks/WebhookEventsApiTest.php b/tests/BigCommerce/Api/Webhooks/WebhookEventsApiTest.php new file mode 100644 index 0000000..651629d --- /dev/null +++ b/tests/BigCommerce/Api/Webhooks/WebhookEventsApiTest.php @@ -0,0 +1,16 @@ +setReturnData('webhooks__events__get_all.json'); + $events = $this->getApi()->webhooks()->events()->getAll()->getEvents(); + + $this->assertEquals('store/sku/inventory/updated', $events[0]->scope); + } +} diff --git a/tests/BigCommerce/Api/Webhooks/WebhooksApiTest.php b/tests/BigCommerce/Api/Webhooks/WebhooksApiTest.php new file mode 100644 index 0000000..94f4466 --- /dev/null +++ b/tests/BigCommerce/Api/Webhooks/WebhooksApiTest.php @@ -0,0 +1,24 @@ +setReturnData('webhooks__get.json'); + $webhook = $this->getApi()->webhook(18048287)->get()->getWebhook(); + + $this->assertEquals('https://665b65a6.ngrok.io/webhooks', $webhook->destination); + $this->assertEquals('string', $webhook->headers['custom']); + } + + public function testCanGetWebhooks() + { + $this->setReturnData('webhooks__get_all.json'); + $webhooks = $this->getApi()->webhooks()->getAll()->getWebhooks(); + $this->assertEquals('store/order/*', $webhooks[0]->scope); + } +} diff --git a/tests/BigCommerce/responses/webhooks__admin__get.json b/tests/BigCommerce/responses/webhooks__admin__get.json new file mode 100644 index 0000000..32658a1 --- /dev/null +++ b/tests/BigCommerce/responses/webhooks__admin__get.json @@ -0,0 +1,35 @@ +{ + "data": { + "emails": [ + "jarrod.swift@aligent.com.au" + ], + "hooks_list": [ + { + "id": 25967773, + "client_id": "6qczasxdcbgvjubghnynimwthwr", + "store_hash": "xxabcdt9gd", + "scope": "store/sku/inventory/updated", + "destination": "https://aligent.com.au/test", + "headers": null, + "is_active": true, + "created_at": 1680144702, + "updated_at": 1680144702, + "events_history_enabled": false + }, + { + "id": 25967774, + "client_id": "6qczasxdcbgvjubghnynimwthwr", + "store_hash": "xxabcdt9gd", + "scope": "store/sku/inventory/updated", + "destination": "https://httpstat.us/200", + "headers": null, + "is_active": true, + "created_at": 1680144907, + "updated_at": 1680144907, + "events_history_enabled": false + } + ], + "blocked_domains": [] + }, + "meta": {} +} \ No newline at end of file diff --git a/tests/BigCommerce/responses/webhooks__events__get_all.json b/tests/BigCommerce/responses/webhooks__events__get_all.json new file mode 100644 index 0000000..c84307a --- /dev/null +++ b/tests/BigCommerce/responses/webhooks__events__get_all.json @@ -0,0 +1,24 @@ +{ + "data": [ + { + "scope": "store/sku/inventory/updated", + "store_id": "25967773", + "data": { + "product": "new", + "stock": 123 + }, + "hash": "0c20013b66c630f5c7473eef26bd71089bb461b4", + "created_at": 1680144702, + "producer": "stores/xxbwhvt3gd" + } + ], + "meta": { + "pagination": { + "total": 1, + "count": 1, + "per_page": 250, + "current_page": 1, + "total_pages": 1 + } + } +} \ No newline at end of file diff --git a/tests/BigCommerce/responses/webhooks__get.json b/tests/BigCommerce/responses/webhooks__get.json new file mode 100644 index 0000000..26f26ef --- /dev/null +++ b/tests/BigCommerce/responses/webhooks__get.json @@ -0,0 +1,16 @@ +{ + "data": { + "id": 18048287, + "client_id": "m9r6keqmo7h7f23btnpwernbez1kglkl", + "store_hash": "sftg45fsd", + "created_at": 1561488106, + "updated_at": 1561488106, + "scope": "store/order/*", + "destination": "https://665b65a6.ngrok.io/webhooks", + "is_active": true, + "headers": { + "custom": "string" + } + }, + "meta": {} +} \ No newline at end of file diff --git a/tests/BigCommerce/responses/webhooks__get_all.json b/tests/BigCommerce/responses/webhooks__get_all.json new file mode 100644 index 0000000..727bebd --- /dev/null +++ b/tests/BigCommerce/responses/webhooks__get_all.json @@ -0,0 +1,16 @@ +{ + "data": [{ + "id": 18048287, + "client_id": "m9r6keqmo7h7f23btnpwernbez1kglkl", + "store_hash": "sftg45fsd", + "created_at": 1561488106, + "updated_at": 1561488106, + "scope": "store/order/*", + "destination": "https://665b65a6.ngrok.io/webhooks", + "is_active": true, + "headers": { + "custom": "string" + } + }], + "meta": {} +} \ No newline at end of file