diff options
author | Côme Chilliet <come.chilliet@nextcloud.com> | 2024-06-06 16:12:36 +0200 |
---|---|---|
committer | Côme Chilliet <91878298+come-nc@users.noreply.github.com> | 2024-06-11 14:10:29 +0200 |
commit | e111d2e26cbc50fb252c940980574a8579ababde (patch) | |
tree | 9337e41a0befdb78cad60290c5e4f26369310b15 | |
parent | 35d5d90dc01b6525fb8aabb4b71aeaa9e7b7a249 (diff) | |
download | nextcloud-server-e111d2e26cbc50fb252c940980574a8579ababde.tar.gz nextcloud-server-e111d2e26cbc50fb252c940980574a8579ababde.zip |
fix: Make webhook event serialization opt-in with a new interface
Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
-rw-r--r-- | apps/webhooks/lib/Db/WebhookListenerMapper.php | 7 | ||||
-rw-r--r-- | apps/webhooks/lib/Listener/WebhooksEventListener.php | 30 | ||||
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/public/EventDispatcher/IWebhookCompatibleEvent.php | 24 | ||||
-rw-r--r-- | lib/public/Files/Events/Node/AbstractNodeEvent.php | 6 | ||||
-rw-r--r-- | lib/public/Files/Events/Node/AbstractNodesEvent.php | 6 |
7 files changed, 45 insertions, 30 deletions
diff --git a/apps/webhooks/lib/Db/WebhookListenerMapper.php b/apps/webhooks/lib/Db/WebhookListenerMapper.php index a4a43a882f5..85c167b0c92 100644 --- a/apps/webhooks/lib/Db/WebhookListenerMapper.php +++ b/apps/webhooks/lib/Db/WebhookListenerMapper.php @@ -14,6 +14,7 @@ use OCP\AppFramework\Db\MultipleObjectsReturnedException; use OCP\AppFramework\Db\QBMapper; use OCP\DB\Exception; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\EventDispatcher\IWebhookCompatibleEvent; use OCP\IDBConnection; /** @@ -68,6 +69,9 @@ class WebhookListenerMapper extends QBMapper { AuthMethod $authMethod, ?array $authData, ): WebhookListener { + if (!class_exists($event) || !is_a($event, IWebhookCompatibleEvent::class, true)) { + throw new \UnexpectedValueException("$event is not an event class compatible with webhooks"); + } $webhookListener = WebhookListener::fromParams( [ 'appId' => $appId, @@ -99,6 +103,9 @@ class WebhookListenerMapper extends QBMapper { AuthMethod $authMethod, ?array $authData, ): WebhookListener { + if (!class_exists($event) || !is_a($event, IWebhookCompatibleEvent::class, true)) { + throw new \UnexpectedValueException("$event is not an event class compatible with webhooks"); + } $webhookListener = WebhookListener::fromParams( [ 'id' => $id, diff --git a/apps/webhooks/lib/Listener/WebhooksEventListener.php b/apps/webhooks/lib/Listener/WebhooksEventListener.php index afe53595e75..37d6863553a 100644 --- a/apps/webhooks/lib/Listener/WebhooksEventListener.php +++ b/apps/webhooks/lib/Listener/WebhooksEventListener.php @@ -15,13 +15,14 @@ use OCA\Webhooks\Service\PHPMongoQuery; use OCP\BackgroundJob\IJobList; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; +use OCP\EventDispatcher\IWebhookCompatibleEvent; use OCP\EventDispatcher\JsonSerializer; use OCP\IUserSession; use Psr\Log\LoggerInterface; /** * The class to handle the share events - * @template-implements IEventListener<Event> + * @template-implements IEventListener<IWebhookCompatibleEvent> */ class WebhooksEventListener implements IEventListener { public function __construct( @@ -55,29 +56,10 @@ class WebhooksEventListener implements IEventListener { } } - private function serializeEvent(Event $event): array|\JsonSerializable { - if ($event instanceof \JsonSerializable) { - return $event; - } else { - /* Event is not serializable, we fallback to reflection to still send something */ - $data = ['class' => $event::class]; - $ref = new \ReflectionClass($event); - foreach ($ref->getMethods() as $method) { - if (str_starts_with($method->getName(), 'get')) { - $key = strtolower(substr($method->getName(), 3)); - $value = $method->invoke($event); - if ($value instanceof \OCP\Files\FileInfo) { - $value = [ - 'id' => $value->getId(), - 'path' => $value->getPath(), - ]; - } - $data[$key] = $value; - } - } - $this->logger->debug('Webhook had to use fallback to serialize event '.$event::class); - return $data; - } + private function serializeEvent(IWebhookCompatibleEvent $event): array { + $data = $event->getWebhookSerializable(); + $data['class'] = $event::class; + return $data; } private function filterMatch(array $filter, array $data): bool { diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 0fe1314644f..dbd9ebc66ab 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -281,6 +281,7 @@ return array( 'OCP\\EventDispatcher\\GenericEvent' => $baseDir . '/lib/public/EventDispatcher/GenericEvent.php', 'OCP\\EventDispatcher\\IEventDispatcher' => $baseDir . '/lib/public/EventDispatcher/IEventDispatcher.php', 'OCP\\EventDispatcher\\IEventListener' => $baseDir . '/lib/public/EventDispatcher/IEventListener.php', + 'OCP\\EventDispatcher\\IWebhookCompatibleEvent' => $baseDir . '/lib/public/EventDispatcher/IWebhookCompatibleEvent.php', 'OCP\\EventDispatcher\\JsonSerializer' => $baseDir . '/lib/public/EventDispatcher/JsonSerializer.php', 'OCP\\Exceptions\\AbortedEventException' => $baseDir . '/lib/public/Exceptions/AbortedEventException.php', 'OCP\\Exceptions\\AppConfigException' => $baseDir . '/lib/public/Exceptions/AppConfigException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index cf52b9026f1..9f3b289cdfc 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -322,6 +322,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\EventDispatcher\\GenericEvent' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/GenericEvent.php', 'OCP\\EventDispatcher\\IEventDispatcher' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/IEventDispatcher.php', 'OCP\\EventDispatcher\\IEventListener' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/IEventListener.php', + 'OCP\\EventDispatcher\\IWebhookCompatibleEvent' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/IWebhookCompatibleEvent.php', 'OCP\\EventDispatcher\\JsonSerializer' => __DIR__ . '/../../..' . '/lib/public/EventDispatcher/JsonSerializer.php', 'OCP\\Exceptions\\AbortedEventException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AbortedEventException.php', 'OCP\\Exceptions\\AppConfigException' => __DIR__ . '/../../..' . '/lib/public/Exceptions/AppConfigException.php', diff --git a/lib/public/EventDispatcher/IWebhookCompatibleEvent.php b/lib/public/EventDispatcher/IWebhookCompatibleEvent.php new file mode 100644 index 00000000000..b13c35c187b --- /dev/null +++ b/lib/public/EventDispatcher/IWebhookCompatibleEvent.php @@ -0,0 +1,24 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\EventDispatcher; + +/** + * Interface for events which can be listened to by webhooks + * + * @since 30.0.0 + */ +interface IWebhookCompatibleEvent { + /** + * Return data to be serialized and sent to the webhook. Will be serialized using json_encode. + * + * @since 30.0.0 + */ + public function getWebhookSerializable(): array; +} diff --git a/lib/public/Files/Events/Node/AbstractNodeEvent.php b/lib/public/Files/Events/Node/AbstractNodeEvent.php index cc27bdd8cfd..64b0e3a3aa5 100644 --- a/lib/public/Files/Events/Node/AbstractNodeEvent.php +++ b/lib/public/Files/Events/Node/AbstractNodeEvent.php @@ -9,13 +9,14 @@ declare(strict_types=1); namespace OCP\Files\Events\Node; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IWebhookCompatibleEvent; use OCP\EventDispatcher\JsonSerializer; use OCP\Files\Node; /** * @since 20.0.0 */ -abstract class AbstractNodeEvent extends Event implements \JsonSerializable { +abstract class AbstractNodeEvent extends Event implements IWebhookCompatibleEvent { /** * @since 20.0.0 */ @@ -34,9 +35,8 @@ abstract class AbstractNodeEvent extends Event implements \JsonSerializable { /** * @since 30.0.0 */ - public function jsonSerialize(): array { + public function getWebhookSerializable(): array { return [ - 'class' => static::class, 'node' => JsonSerializer::serializeFileInfo($this->node), ]; } diff --git a/lib/public/Files/Events/Node/AbstractNodesEvent.php b/lib/public/Files/Events/Node/AbstractNodesEvent.php index b5fd1b75898..7941a9e596a 100644 --- a/lib/public/Files/Events/Node/AbstractNodesEvent.php +++ b/lib/public/Files/Events/Node/AbstractNodesEvent.php @@ -9,13 +9,14 @@ declare(strict_types=1); namespace OCP\Files\Events\Node; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IWebhookCompatibleEvent; use OCP\EventDispatcher\JsonSerializer; use OCP\Files\Node; /** * @since 20.0.0 */ -abstract class AbstractNodesEvent extends Event { +abstract class AbstractNodesEvent extends Event implements IWebhookCompatibleEvent { /** * @since 20.0.0 */ @@ -42,9 +43,8 @@ abstract class AbstractNodesEvent extends Event { /** * @since 30.0.0 */ - public function jsonSerialize(): array { + public function getWebhookSerializable(): array { return [ - 'class' => static::class, 'source' => JsonSerializer::serializeFileInfo($this->source), 'target' => JsonSerializer::serializeFileInfo($this->target), ]; |