fix: Make webhook event serialization opt-in with a new interface

Signed-off-by: Côme Chilliet <come.chilliet@nextcloud.com>
pull/45475/head
Côme Chilliet 2 years ago committed by Côme Chilliet
parent 35d5d90dc0
commit e111d2e26c
  1. 7
      apps/webhooks/lib/Db/WebhookListenerMapper.php
  2. 30
      apps/webhooks/lib/Listener/WebhooksEventListener.php
  3. 1
      lib/composer/composer/autoload_classmap.php
  4. 1
      lib/composer/composer/autoload_static.php
  5. 24
      lib/public/EventDispatcher/IWebhookCompatibleEvent.php
  6. 6
      lib/public/Files/Events/Node/AbstractNodeEvent.php
  7. 6
      lib/public/Files/Events/Node/AbstractNodesEvent.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,

@ -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 {

@ -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',

@ -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',

@ -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;
}

@ -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),
];
}

@ -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),
];

Loading…
Cancel
Save