aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorprovokateurin <kate@provokateurin.de>2025-01-20 15:05:27 +0100
committerprovokateurin <kate@provokateurin.de>2025-05-19 13:54:51 +0200
commit6818aa9b12743a95098b9ea98c2083dee8805c36 (patch)
tree292dedf603c97175c20b7d36150ea6270703d83e
parent13f23061e87b182f23dfd9757273a1b66419a7e3 (diff)
downloadnextcloud-server-feat/mountmanager/emit-events.tar.gz
nextcloud-server-feat/mountmanager/emit-events.zip
feat(UserMountCache): Emit events for added, removed and updated mountsfeat/mountmanager/emit-events
Signed-off-by: provokateurin <kate@provokateurin.de>
-rw-r--r--lib/composer/composer/autoload_classmap.php3
-rw-r--r--lib/composer/composer/autoload_static.php3
-rw-r--r--lib/private/Files/Config/UserMountCache.php31
-rw-r--r--lib/public/Files/Config/Event/UserMountAddedEvent.php27
-rw-r--r--lib/public/Files/Config/Event/UserMountRemovedEvent.php27
-rw-r--r--lib/public/Files/Config/Event/UserMountUpdatedEvent.php28
-rw-r--r--tests/lib/Files/Config/UserMountCacheTest.php85
7 files changed, 180 insertions, 24 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index c0c086e4038..6a2015de300 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -381,6 +381,9 @@ return array(
'OCP\\Files\\Cache\\IScanner' => $baseDir . '/lib/public/Files/Cache/IScanner.php',
'OCP\\Files\\Cache\\IUpdater' => $baseDir . '/lib/public/Files/Cache/IUpdater.php',
'OCP\\Files\\Cache\\IWatcher' => $baseDir . '/lib/public/Files/Cache/IWatcher.php',
+ 'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountAddedEvent.php',
+ 'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php',
+ 'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php',
'OCP\\Files\\Config\\ICachedMountFileInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountFileInfo.php',
'OCP\\Files\\Config\\ICachedMountInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountInfo.php',
'OCP\\Files\\Config\\IHomeMountProvider' => $baseDir . '/lib/public/Files/Config/IHomeMountProvider.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index f2f817877d2..704cac28332 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -422,6 +422,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Files\\Cache\\IScanner' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IScanner.php',
'OCP\\Files\\Cache\\IUpdater' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IUpdater.php',
'OCP\\Files\\Cache\\IWatcher' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IWatcher.php',
+ 'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountAddedEvent.php',
+ 'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php',
+ 'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php',
'OCP\\Files\\Config\\ICachedMountFileInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountFileInfo.php',
'OCP\\Files\\Config\\ICachedMountInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountInfo.php',
'OCP\\Files\\Config\\IHomeMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IHomeMountProvider.php',
diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php
index 9c1e2314262..09ac6d1416a 100644
--- a/lib/private/Files/Config/UserMountCache.php
+++ b/lib/private/Files/Config/UserMountCache.php
@@ -11,6 +11,10 @@ use OC\User\LazyUser;
use OCP\Cache\CappedMemoryCache;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Diagnostics\IEventLogger;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Config\Event\UserMountAddedEvent;
+use OCP\Files\Config\Event\UserMountRemovedEvent;
+use OCP\Files\Config\Event\UserMountUpdatedEvent;
use OCP\Files\Config\ICachedMountFileInfo;
use OCP\Files\Config\ICachedMountInfo;
use OCP\Files\Config\IUserMountCache;
@@ -46,6 +50,7 @@ class UserMountCache implements IUserMountCache {
private IUserManager $userManager,
private LoggerInterface $logger,
private IEventLogger $eventLogger,
+ private IEventDispatcher $eventDispatcher,
) {
$this->cacheInfoCache = new CappedMemoryCache();
$this->internalPathCache = new CappedMemoryCache();
@@ -108,17 +113,29 @@ class UserMountCache implements IUserMountCache {
$this->removeFromCache($mount);
unset($this->mountsForUsers[$userUID][$mount->getKey()]);
}
- foreach ($changedMounts as $mount) {
- $this->logger->debug("Updating mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]);
- $this->updateCachedMount($mount);
+ foreach ($changedMounts as $mountPair) {
+ $newMount = $mountPair[1];
+ $this->logger->debug("Updating mount '{$newMount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $newMount->getMountProvider()]);
+ $this->updateCachedMount($newMount);
/** @psalm-suppress InvalidArgument */
- $this->mountsForUsers[$userUID][$mount->getKey()] = $mount;
+ $this->mountsForUsers[$userUID][$newMount->getKey()] = $newMount;
}
$this->connection->commit();
} catch (\Throwable $e) {
$this->connection->rollBack();
throw $e;
}
+
+ // Only fire events after all mounts have already been adjusted in the database.
+ foreach ($addedMounts as $mount) {
+ $this->eventDispatcher->dispatchTyped(new UserMountAddedEvent($mount));
+ }
+ foreach ($removedMounts as $mount) {
+ $this->eventDispatcher->dispatchTyped(new UserMountRemovedEvent($mount));
+ }
+ foreach ($changedMounts as $mountPair) {
+ $this->eventDispatcher->dispatchTyped(new UserMountUpdatedEvent($mountPair[0], $mountPair[1]));
+ }
}
$this->eventLogger->end('fs:setup:user:register');
}
@@ -126,9 +143,9 @@ class UserMountCache implements IUserMountCache {
/**
* @param array<string, ICachedMountInfo> $newMounts
* @param array<string, ICachedMountInfo> $cachedMounts
- * @return ICachedMountInfo[]
+ * @return list<list{0: ICachedMountInfo, 1: ICachedMountInfo}> Pairs of old and new mounts
*/
- private function findChangedMounts(array $newMounts, array $cachedMounts) {
+ private function findChangedMounts(array $newMounts, array $cachedMounts): array {
$changed = [];
foreach ($cachedMounts as $key => $cachedMount) {
if (isset($newMounts[$key])) {
@@ -138,7 +155,7 @@ class UserMountCache implements IUserMountCache {
$newMount->getMountId() !== $cachedMount->getMountId() ||
$newMount->getMountProvider() !== $cachedMount->getMountProvider()
) {
- $changed[] = $newMount;
+ $changed[] = [$cachedMount, $newMount];
}
}
}
diff --git a/lib/public/Files/Config/Event/UserMountAddedEvent.php b/lib/public/Files/Config/Event/UserMountAddedEvent.php
new file mode 100644
index 00000000000..45cfadc7967
--- /dev/null
+++ b/lib/public/Files/Config/Event/UserMountAddedEvent.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Files\Config\Event;
+
+use OCP\EventDispatcher\Event;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\Files\Mount\IMountPoint;
+
+/**
+ * Event emitted when a user mount was added.
+ *
+ * @since 31.0.0
+ */
+class UserMountAddedEvent extends Event {
+ public function __construct(
+ public readonly IMountPoint|ICachedMountInfo $mountPoint,
+ ) {
+ parent::__construct();
+ }
+}
diff --git a/lib/public/Files/Config/Event/UserMountRemovedEvent.php b/lib/public/Files/Config/Event/UserMountRemovedEvent.php
new file mode 100644
index 00000000000..c6db238a9b5
--- /dev/null
+++ b/lib/public/Files/Config/Event/UserMountRemovedEvent.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Files\Config\Event;
+
+use OCP\EventDispatcher\Event;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\Files\Mount\IMountPoint;
+
+/**
+ * Event emitted when a user mount was removed.
+ *
+ * @since 31.0.0
+ */
+class UserMountRemovedEvent extends Event {
+ public function __construct(
+ public readonly IMountPoint|ICachedMountInfo $mountPoint,
+ ) {
+ parent::__construct();
+ }
+}
diff --git a/lib/public/Files/Config/Event/UserMountUpdatedEvent.php b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php
new file mode 100644
index 00000000000..6c5fd0524e4
--- /dev/null
+++ b/lib/public/Files/Config/Event/UserMountUpdatedEvent.php
@@ -0,0 +1,28 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace OCP\Files\Config\Event;
+
+use OCP\EventDispatcher\Event;
+use OCP\Files\Config\ICachedMountInfo;
+use OCP\Files\Mount\IMountPoint;
+
+/**
+ * Event emitted when a user mount was moved.
+ *
+ * @since 31.0.0
+ */
+class UserMountUpdatedEvent extends Event {
+ public function __construct(
+ public readonly IMountPoint|ICachedMountInfo $oldMountPoint,
+ public readonly IMountPoint|ICachedMountInfo $newMountPoint,
+ ) {
+ parent::__construct();
+ }
+}
diff --git a/tests/lib/Files/Config/UserMountCacheTest.php b/tests/lib/Files/Config/UserMountCacheTest.php
index 88b8b7767dd..88c0ceaef08 100644
--- a/tests/lib/Files/Config/UserMountCacheTest.php
+++ b/tests/lib/Files/Config/UserMountCacheTest.php
@@ -10,6 +10,7 @@ namespace Test\Files\Config;
use OC\DB\Exceptions\DbalException;
use OC\DB\QueryBuilder\Literal;
use OC\Files\Cache\Cache;
+use OC\Files\Config\UserMountCache;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Storage;
use OC\User\Manager;
@@ -17,6 +18,9 @@ use OCP\Cache\CappedMemoryCache;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Config\Event\UserMountAddedEvent;
+use OCP\Files\Config\Event\UserMountRemovedEvent;
+use OCP\Files\Config\Event\UserMountUpdatedEvent;
use OCP\Files\Config\ICachedMountInfo;
use OCP\ICacheFactory;
use OCP\IConfig;
@@ -30,28 +34,19 @@ use Test\Util\User\Dummy;
* @group DB
*/
class UserMountCacheTest extends TestCase {
- /**
- * @var IDBConnection
- */
- private $connection;
-
- /**
- * @var IUserManager
- */
- private $userManager;
-
- /**
- * @var \OC\Files\Config\UserMountCache
- */
- private $cache;
-
- private $fileIds = [];
+ private IDBConnection $connection;
+ private IUserManager $userManager;
+ private IEventDispatcher $eventDispatcher;
+ private UserMountCache $cache;
+ private array $fileIds = [];
protected function setUp(): void {
parent::setUp();
$this->fileIds = [];
+
$this->connection = \OC::$server->getDatabaseConnection();
+
$config = $this->getMockBuilder(IConfig::class)
->disableOriginalConstructor()
->getMock();
@@ -63,13 +58,22 @@ class UserMountCacheTest extends TestCase {
->expects($this->any())
->method('getAppValue')
->willReturnArgument(2);
+
$this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class));
$userBackend = new Dummy();
$userBackend->createUser('u1', '');
$userBackend->createUser('u2', '');
$userBackend->createUser('u3', '');
$this->userManager->registerBackend($userBackend);
- $this->cache = new \OC\Files\Config\UserMountCache($this->connection, $this->userManager, $this->createMock(LoggerInterface::class), $this->createMock(IEventLogger::class));
+
+ $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
+
+ $this->cache = new UserMountCache($this->connection,
+ $this->userManager,
+ $this->createMock(LoggerInterface::class),
+ $this->createMock(IEventLogger::class),
+ $this->eventDispatcher,
+ );
}
protected function tearDown(): void {
@@ -121,6 +125,11 @@ class UserMountCacheTest extends TestCase {
}
public function testNewMounts(): void {
+ $this->eventDispatcher
+ ->expects($this->once())
+ ->method('dispatchTyped')
+ ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
+
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
@@ -141,6 +150,11 @@ class UserMountCacheTest extends TestCase {
}
public function testSameMounts(): void {
+ $this->eventDispatcher
+ ->expects($this->once())
+ ->method('dispatchTyped')
+ ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
+
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
@@ -165,6 +179,18 @@ class UserMountCacheTest extends TestCase {
}
public function testRemoveMounts(): void {
+ $operation = 0;
+ $this->eventDispatcher
+ ->expects($this->exactly(2))
+ ->method('dispatchTyped')
+ ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
+ return match(++$operation) {
+ 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/asd/',
+ 2 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/asd/',
+ default => false,
+ };
+ }));
+
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
@@ -184,6 +210,19 @@ class UserMountCacheTest extends TestCase {
}
public function testChangeMounts(): void {
+ $operation = 0;
+ $this->eventDispatcher
+ ->expects($this->exactly(3))
+ ->method('dispatchTyped')
+ ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
+ return match(++$operation) {
+ 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/bar/',
+ 2 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
+ 3 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/bar/',
+ default => false,
+ };
+ }));
+
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);
@@ -207,6 +246,18 @@ class UserMountCacheTest extends TestCase {
}
public function testChangeMountId(): void {
+ $operation = 0;
+ $this->eventDispatcher
+ ->expects($this->exactly(2))
+ ->method('dispatchTyped')
+ ->with($this->callback(function (UserMountAddedEvent|UserMountUpdatedEvent $event) use (&$operation) {
+ return match(++$operation) {
+ 1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
+ 2 => $event instanceof UserMountUpdatedEvent && $event->oldMountPoint->getMountId() === null && $event->newMountPoint->getMountId() === 1,
+ default => false,
+ };
+ }));
+
$user = $this->userManager->get('u1');
[$storage] = $this->getStorage(10);