aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorprovokateurin <kate@provokateurin.de>2025-01-20 15:05:27 +0100
committerAndy Scherzinger <info@andy-scherzinger.de>2025-05-25 16:46:53 +0200
commit29d69826b6d9007ddf7a46b5879c52c727031e20 (patch)
treeb7f8c1dc4733a0fc5d81cc17ace2d2076b18f988
parenta9d0c2164fc4f43378640b9314cc2f482ae44ff9 (diff)
downloadnextcloud-server-backport/50157/stable31.tar.gz
nextcloud-server-backport/50157/stable31.zip
feat(UserMountCache): Emit events for added, removed and updated mountsbackport/50157/stable31
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.php30
-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, 179 insertions, 24 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index 7b904978219..5be33f27523 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -379,6 +379,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 98ed46e5d96..5c7ebf20f1d 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -428,6 +428,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 7d9ecc16f76..7c2be4e80e8 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;
@@ -24,7 +28,6 @@ use Psr\Log\LoggerInterface;
* Cache mounts points per user in the cache so we can easily look them up
*/
class UserMountCache implements IUserMountCache {
-
/**
* Cached mount info.
* @var CappedMemoryCache<ICachedMountInfo[]>
@@ -46,6 +49,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();
@@ -106,16 +110,28 @@ class UserMountCache implements IUserMountCache {
$this->removeFromCache($mount);
unset($this->mountsForUsers[$userUID][$mount->getKey()]);
}
- foreach ($changedMounts as $mount) {
- $this->updateCachedMount($mount);
+ foreach ($changedMounts as $mountPair) {
+ $newMount = $mountPair[1];
+ $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');
}
@@ -123,9 +139,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])) {
@@ -135,7 +151,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..200d12daaf4
--- /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 30.0.12
+ */
+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..202c73ad38d
--- /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 30.0.12
+ */
+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..78752e594e4
--- /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 30.0.12
+ */
+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 1efc56c1908..d61fcf636b7 100644
--- a/tests/lib/Files/Config/UserMountCacheTest.php
+++ b/tests/lib/Files/Config/UserMountCacheTest.php
@@ -9,6 +9,7 @@ namespace Test\Files\Config;
use OC\DB\Exceptions\DbalException;
use OC\DB\QueryBuilder\Literal;
+use OC\Files\Config\UserMountCache;
use OC\Files\Mount\MountPoint;
use OC\Files\Storage\Storage;
use OC\User\Manager;
@@ -16,6 +17,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;
@@ -29,28 +33,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();
@@ -62,13 +57,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 {
@@ -126,6 +130,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);
@@ -146,6 +155,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);
@@ -170,6 +184,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);
@@ -189,6 +215,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);
@@ -212,6 +251,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);