From: Côme Chilliet Date: Thu, 6 Jun 2024 14:12:36 +0000 (+0200) Subject: fix: Make webhook event serialization opt-in with a new interface X-Git-Tag: v30.0.0beta1~341^2~14 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e111d2e26cbc50fb252c940980574a8579ababde;p=nextcloud-server.git fix: Make webhook event serialization opt-in with a new interface Signed-off-by: Côme Chilliet --- 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 + * @template-implements IEventListener */ 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 @@ + 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), ];