diff --git a/apps/webhook_listeners/lib/AppInfo/Application.php b/apps/webhook_listeners/lib/AppInfo/Application.php index d1ffa5db49b..30f2e0969f6 100644 --- a/apps/webhook_listeners/lib/AppInfo/Application.php +++ b/apps/webhook_listeners/lib/AppInfo/Application.php @@ -16,6 +16,7 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\EventDispatcher\IEventDispatcher; +use OCP\IUserSession; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; @@ -40,9 +41,10 @@ class Application extends App implements IBootstrap { ): void { /** @var WebhookListenerMapper */ $mapper = $container->get(WebhookListenerMapper::class); + $userSession = $container->get(IUserSession::class); /* Listen to all events with at least one webhook configured */ - $configuredEvents = $mapper->getAllConfiguredEvents(); + $configuredEvents = $mapper->getAllConfiguredEvents($userSession->getUser()?->getUID()); foreach ($configuredEvents as $eventName) { $logger->debug("Listening to {$eventName}"); $dispatcher->addServiceListener( diff --git a/apps/webhook_listeners/lib/Controller/WebhooksController.php b/apps/webhook_listeners/lib/Controller/WebhooksController.php index 5b097c84a3c..a4de0c8d342 100644 --- a/apps/webhook_listeners/lib/Controller/WebhooksController.php +++ b/apps/webhook_listeners/lib/Controller/WebhooksController.php @@ -126,6 +126,7 @@ class WebhooksController extends OCSController { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, ?string $authMethod, #[\SensitiveParameter] @@ -150,6 +151,7 @@ class WebhooksController extends OCSController { $uri, $event, $eventFilter, + $userIdFilter, $headers, $authMethod, $authData, @@ -193,6 +195,7 @@ class WebhooksController extends OCSController { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, ?string $authMethod, #[\SensitiveParameter] @@ -218,6 +221,7 @@ class WebhooksController extends OCSController { $uri, $event, $eventFilter, + $userIdFilter, $headers, $authMethod, $authData, diff --git a/apps/webhook_listeners/lib/Db/WebhookListener.php b/apps/webhook_listeners/lib/Db/WebhookListener.php index e9b63e01472..680d47798d5 100644 --- a/apps/webhook_listeners/lib/Db/WebhookListener.php +++ b/apps/webhook_listeners/lib/Db/WebhookListener.php @@ -59,6 +59,12 @@ class WebhookListener extends Entity implements \JsonSerializable { */ protected $eventFilter; + /** + * @var string + * If not empty, id of the user that needs to be connected for the webhook to trigger + */ + protected $userIdFilter; + /** * @var ?array */ @@ -90,6 +96,7 @@ class WebhookListener extends Entity implements \JsonSerializable { $this->addType('uri', 'string'); $this->addType('event', 'string'); $this->addType('eventFilter', 'json'); + $this->addType('userIdFilter', 'string'); $this->addType('headers', 'json'); $this->addType('authMethod', 'string'); $this->addType('authData', 'string'); diff --git a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php index a1fe4ceee8d..ad8c287ad43 100644 --- a/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php +++ b/apps/webhook_listeners/lib/Db/WebhookListenerMapper.php @@ -25,7 +25,7 @@ use OCP\IDBConnection; class WebhookListenerMapper extends QBMapper { public const TABLE_NAME = 'webhook_listeners'; - private const EVENTS_CACHE_KEY = 'eventsUsedInWebhooks'; + private const EVENTS_CACHE_KEY_PREFIX = 'eventsUsedInWebhooks'; private ?ICache $cache = null; @@ -77,6 +77,7 @@ class WebhookListenerMapper extends QBMapper { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, AuthMethod $authMethod, #[\SensitiveParameter] @@ -95,12 +96,13 @@ class WebhookListenerMapper extends QBMapper { 'uri' => $uri, 'event' => $event, 'eventFilter' => $eventFilter ?? [], + 'userIdFilter' => $userIdFilter ?? '', 'headers' => $headers, 'authMethod' => $authMethod->value, ] ); $webhookListener->setAuthDataClear($authData); - $this->cache?->remove(self::EVENTS_CACHE_KEY); + $this->cache?->remove($this->buildCacheKey($userIdFilter)); return $this->insert($webhookListener); } @@ -115,6 +117,7 @@ class WebhookListenerMapper extends QBMapper { string $uri, string $event, ?array $eventFilter, + ?string $userIdFilter, ?array $headers, AuthMethod $authMethod, #[\SensitiveParameter] @@ -134,12 +137,13 @@ class WebhookListenerMapper extends QBMapper { 'uri' => $uri, 'event' => $event, 'eventFilter' => $eventFilter ?? [], + 'userIdFilter' => $userIdFilter ?? '', 'headers' => $headers, 'authMethod' => $authMethod->value, ] ); $webhookListener->setAuthDataClear($authData); - $this->cache?->remove(self::EVENTS_CACHE_KEY); + $this->cache?->remove($this->buildCacheKey($userIdFilter)); return $this->update($webhookListener); } @@ -159,11 +163,12 @@ class WebhookListenerMapper extends QBMapper { * @throws Exception * @return list */ - private function getAllConfiguredEventsFromDatabase(): array { + private function getAllConfiguredEventsFromDatabase(string $userId): array { $qb = $this->db->getQueryBuilder(); $qb->selectDistinct('event') - ->from($this->getTableName()); + ->from($this->getTableName()) + ->where($qb->expr()->in('user_id_filter', $qb->createNamedParameter(['',$userId], IQueryBuilder::PARAM_STR_ARRAY), IQueryBuilder::PARAM_STR)); $result = $qb->executeQuery(); @@ -181,14 +186,15 @@ class WebhookListenerMapper extends QBMapper { * @throws Exception * @return list */ - public function getAllConfiguredEvents(): array { - $events = $this->cache?->get(self::EVENTS_CACHE_KEY); + public function getAllConfiguredEvents(?string $userId = null): array { + $cacheKey = $this->buildCacheKey($userId); + $events = $this->cache?->get($cacheKey); if ($events !== null) { return json_decode($events); } - $events = $this->getAllConfiguredEventsFromDatabase(); + $events = $this->getAllConfiguredEventsFromDatabase($userId ?? ''); // cache for 5 minutes - $this->cache?->set(self::EVENTS_CACHE_KEY, json_encode($events), 300); + $this->cache?->set($cacheKey, json_encode($events), 300); return $events; } @@ -217,4 +223,8 @@ class WebhookListenerMapper extends QBMapper { return $this->findEntities($qb); } + + private function buildCacheKey(?string $userIdFilter = ''): string { + return self::EVENTS_CACHE_KEY_PREFIX.'_'.($userIdFilter ?? ''); + } } diff --git a/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php b/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php index 44f2476dd44..6693c8ecf3f 100755 --- a/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php +++ b/apps/webhook_listeners/lib/Migration/Version1000Date20240527153425.php @@ -53,6 +53,10 @@ class Version1000Date20240527153425 extends SimpleMigrationStep { $table->addColumn('event_filter', Types::TEXT, [ 'notnull' => false, ]); + $table->addColumn('user_id_filter', Types::STRING, [ + 'notnull' => true, + 'length' => 64, + ]); $table->addColumn('headers', Types::TEXT, [ 'notnull' => false, ]); diff --git a/apps/webhook_listeners/lib/ResponseDefinitions.php b/apps/webhook_listeners/lib/ResponseDefinitions.php index cb33f93e8ff..725e00b118a 100644 --- a/apps/webhook_listeners/lib/ResponseDefinitions.php +++ b/apps/webhook_listeners/lib/ResponseDefinitions.php @@ -17,6 +17,7 @@ namespace OCA\WebhookListeners; * uri: string, * event?: string, * eventFilter?: array, + * userIdFilter?: string, * headers?: array, * authMethod: string, * authData?: array, diff --git a/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php b/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php index fc42a0a9597..327d5740077 100644 --- a/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php +++ b/apps/webhook_listeners/tests/Db/WebhookListenerMapperTest.php @@ -58,6 +58,7 @@ class WebhookListenerMapperTest extends TestCase { UserCreatedEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -72,6 +73,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -92,6 +94,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::None, null, ); @@ -111,6 +114,7 @@ class WebhookListenerMapperTest extends TestCase { NodeWrittenEvent::class, null, null, + null, AuthMethod::Header, ['secretHeader' => 'header'], );