Skip to content

Commit 76d37a3

Browse files
Merge pull request #52987 from nextcloud/backport/50157/stable31
2 parents b09e0ea + 29d6982 commit 76d37a3

File tree

7 files changed

+179
-24
lines changed

7 files changed

+179
-24
lines changed

lib/composer/composer/autoload_classmap.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,9 @@
379379
'OCP\\Files\\Cache\\IScanner' => $baseDir . '/lib/public/Files/Cache/IScanner.php',
380380
'OCP\\Files\\Cache\\IUpdater' => $baseDir . '/lib/public/Files/Cache/IUpdater.php',
381381
'OCP\\Files\\Cache\\IWatcher' => $baseDir . '/lib/public/Files/Cache/IWatcher.php',
382+
'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountAddedEvent.php',
383+
'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php',
384+
'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => $baseDir . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php',
382385
'OCP\\Files\\Config\\ICachedMountFileInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountFileInfo.php',
383386
'OCP\\Files\\Config\\ICachedMountInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountInfo.php',
384387
'OCP\\Files\\Config\\IHomeMountProvider' => $baseDir . '/lib/public/Files/Config/IHomeMountProvider.php',

lib/composer/composer/autoload_static.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
428428
'OCP\\Files\\Cache\\IScanner' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IScanner.php',
429429
'OCP\\Files\\Cache\\IUpdater' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IUpdater.php',
430430
'OCP\\Files\\Cache\\IWatcher' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/IWatcher.php',
431+
'OCP\\Files\\Config\\Event\\UserMountAddedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountAddedEvent.php',
432+
'OCP\\Files\\Config\\Event\\UserMountRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountRemovedEvent.php',
433+
'OCP\\Files\\Config\\Event\\UserMountUpdatedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Config/Event/UserMountUpdatedEvent.php',
431434
'OCP\\Files\\Config\\ICachedMountFileInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountFileInfo.php',
432435
'OCP\\Files\\Config\\ICachedMountInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountInfo.php',
433436
'OCP\\Files\\Config\\IHomeMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IHomeMountProvider.php',

lib/private/Files/Config/UserMountCache.php

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
use OCP\Cache\CappedMemoryCache;
1212
use OCP\DB\QueryBuilder\IQueryBuilder;
1313
use OCP\Diagnostics\IEventLogger;
14+
use OCP\EventDispatcher\IEventDispatcher;
15+
use OCP\Files\Config\Event\UserMountAddedEvent;
16+
use OCP\Files\Config\Event\UserMountRemovedEvent;
17+
use OCP\Files\Config\Event\UserMountUpdatedEvent;
1418
use OCP\Files\Config\ICachedMountFileInfo;
1519
use OCP\Files\Config\ICachedMountInfo;
1620
use OCP\Files\Config\IUserMountCache;
@@ -24,7 +28,6 @@
2428
* Cache mounts points per user in the cache so we can easily look them up
2529
*/
2630
class UserMountCache implements IUserMountCache {
27-
2831
/**
2932
* Cached mount info.
3033
* @var CappedMemoryCache<ICachedMountInfo[]>
@@ -46,6 +49,7 @@ public function __construct(
4649
private IUserManager $userManager,
4750
private LoggerInterface $logger,
4851
private IEventLogger $eventLogger,
52+
private IEventDispatcher $eventDispatcher,
4953
) {
5054
$this->cacheInfoCache = new CappedMemoryCache();
5155
$this->internalPathCache = new CappedMemoryCache();
@@ -106,26 +110,38 @@ public function registerMounts(IUser $user, array $mounts, ?array $mountProvider
106110
$this->removeFromCache($mount);
107111
unset($this->mountsForUsers[$userUID][$mount->getKey()]);
108112
}
109-
foreach ($changedMounts as $mount) {
110-
$this->updateCachedMount($mount);
113+
foreach ($changedMounts as $mountPair) {
114+
$newMount = $mountPair[1];
115+
$this->updateCachedMount($newMount);
111116
/** @psalm-suppress InvalidArgument */
112-
$this->mountsForUsers[$userUID][$mount->getKey()] = $mount;
117+
$this->mountsForUsers[$userUID][$newMount->getKey()] = $newMount;
113118
}
114119
$this->connection->commit();
115120
} catch (\Throwable $e) {
116121
$this->connection->rollBack();
117122
throw $e;
118123
}
124+
125+
// Only fire events after all mounts have already been adjusted in the database.
126+
foreach ($addedMounts as $mount) {
127+
$this->eventDispatcher->dispatchTyped(new UserMountAddedEvent($mount));
128+
}
129+
foreach ($removedMounts as $mount) {
130+
$this->eventDispatcher->dispatchTyped(new UserMountRemovedEvent($mount));
131+
}
132+
foreach ($changedMounts as $mountPair) {
133+
$this->eventDispatcher->dispatchTyped(new UserMountUpdatedEvent($mountPair[0], $mountPair[1]));
134+
}
119135
}
120136
$this->eventLogger->end('fs:setup:user:register');
121137
}
122138

123139
/**
124140
* @param array<string, ICachedMountInfo> $newMounts
125141
* @param array<string, ICachedMountInfo> $cachedMounts
126-
* @return ICachedMountInfo[]
142+
* @return list<list{0: ICachedMountInfo, 1: ICachedMountInfo}> Pairs of old and new mounts
127143
*/
128-
private function findChangedMounts(array $newMounts, array $cachedMounts) {
144+
private function findChangedMounts(array $newMounts, array $cachedMounts): array {
129145
$changed = [];
130146
foreach ($cachedMounts as $key => $cachedMount) {
131147
if (isset($newMounts[$key])) {
@@ -135,7 +151,7 @@ private function findChangedMounts(array $newMounts, array $cachedMounts) {
135151
$newMount->getMountId() !== $cachedMount->getMountId() ||
136152
$newMount->getMountProvider() !== $cachedMount->getMountProvider()
137153
) {
138-
$changed[] = $newMount;
154+
$changed[] = [$cachedMount, $newMount];
139155
}
140156
}
141157
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Config\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Config\ICachedMountInfo;
14+
use OCP\Files\Mount\IMountPoint;
15+
16+
/**
17+
* Event emitted when a user mount was added.
18+
*
19+
* @since 30.0.12
20+
*/
21+
class UserMountAddedEvent extends Event {
22+
public function __construct(
23+
public readonly IMountPoint|ICachedMountInfo $mountPoint,
24+
) {
25+
parent::__construct();
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Config\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Config\ICachedMountInfo;
14+
use OCP\Files\Mount\IMountPoint;
15+
16+
/**
17+
* Event emitted when a user mount was removed.
18+
*
19+
* @since 30.0.12
20+
*/
21+
class UserMountRemovedEvent extends Event {
22+
public function __construct(
23+
public readonly IMountPoint|ICachedMountInfo $mountPoint,
24+
) {
25+
parent::__construct();
26+
}
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCP\Files\Config\Event;
11+
12+
use OCP\EventDispatcher\Event;
13+
use OCP\Files\Config\ICachedMountInfo;
14+
use OCP\Files\Mount\IMountPoint;
15+
16+
/**
17+
* Event emitted when a user mount was moved.
18+
*
19+
* @since 30.0.12
20+
*/
21+
class UserMountUpdatedEvent extends Event {
22+
public function __construct(
23+
public readonly IMountPoint|ICachedMountInfo $oldMountPoint,
24+
public readonly IMountPoint|ICachedMountInfo $newMountPoint,
25+
) {
26+
parent::__construct();
27+
}
28+
}

tests/lib/Files/Config/UserMountCacheTest.php

Lines changed: 68 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99

1010
use OC\DB\Exceptions\DbalException;
1111
use OC\DB\QueryBuilder\Literal;
12+
use OC\Files\Config\UserMountCache;
1213
use OC\Files\Mount\MountPoint;
1314
use OC\Files\Storage\Storage;
1415
use OC\User\Manager;
1516
use OCP\Cache\CappedMemoryCache;
1617
use OCP\DB\QueryBuilder\IQueryBuilder;
1718
use OCP\Diagnostics\IEventLogger;
1819
use OCP\EventDispatcher\IEventDispatcher;
20+
use OCP\Files\Config\Event\UserMountAddedEvent;
21+
use OCP\Files\Config\Event\UserMountRemovedEvent;
22+
use OCP\Files\Config\Event\UserMountUpdatedEvent;
1923
use OCP\Files\Config\ICachedMountInfo;
2024
use OCP\ICacheFactory;
2125
use OCP\IConfig;
@@ -29,28 +33,19 @@
2933
* @group DB
3034
*/
3135
class UserMountCacheTest extends TestCase {
32-
/**
33-
* @var IDBConnection
34-
*/
35-
private $connection;
36-
37-
/**
38-
* @var IUserManager
39-
*/
40-
private $userManager;
41-
42-
/**
43-
* @var \OC\Files\Config\UserMountCache
44-
*/
45-
private $cache;
46-
47-
private $fileIds = [];
36+
private IDBConnection $connection;
37+
private IUserManager $userManager;
38+
private IEventDispatcher $eventDispatcher;
39+
private UserMountCache $cache;
40+
private array $fileIds = [];
4841

4942
protected function setUp(): void {
5043
parent::setUp();
5144

5245
$this->fileIds = [];
46+
5347
$this->connection = \OC::$server->getDatabaseConnection();
48+
5449
$config = $this->getMockBuilder(IConfig::class)
5550
->disableOriginalConstructor()
5651
->getMock();
@@ -62,13 +57,22 @@ protected function setUp(): void {
6257
->expects($this->any())
6358
->method('getAppValue')
6459
->willReturnArgument(2);
60+
6561
$this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class));
6662
$userBackend = new Dummy();
6763
$userBackend->createUser('u1', '');
6864
$userBackend->createUser('u2', '');
6965
$userBackend->createUser('u3', '');
7066
$this->userManager->registerBackend($userBackend);
71-
$this->cache = new \OC\Files\Config\UserMountCache($this->connection, $this->userManager, $this->createMock(LoggerInterface::class), $this->createMock(IEventLogger::class));
67+
68+
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
69+
70+
$this->cache = new UserMountCache($this->connection,
71+
$this->userManager,
72+
$this->createMock(LoggerInterface::class),
73+
$this->createMock(IEventLogger::class),
74+
$this->eventDispatcher,
75+
);
7276
}
7377

7478
protected function tearDown(): void {
@@ -126,6 +130,11 @@ private function keyForMount(MountPoint $mount): string {
126130
}
127131

128132
public function testNewMounts(): void {
133+
$this->eventDispatcher
134+
->expects($this->once())
135+
->method('dispatchTyped')
136+
->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
137+
129138
$user = $this->userManager->get('u1');
130139

131140
[$storage] = $this->getStorage(10);
@@ -146,6 +155,11 @@ public function testNewMounts(): void {
146155
}
147156

148157
public function testSameMounts(): void {
158+
$this->eventDispatcher
159+
->expects($this->once())
160+
->method('dispatchTyped')
161+
->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
162+
149163
$user = $this->userManager->get('u1');
150164

151165
[$storage] = $this->getStorage(10);
@@ -170,6 +184,18 @@ public function testSameMounts(): void {
170184
}
171185

172186
public function testRemoveMounts(): void {
187+
$operation = 0;
188+
$this->eventDispatcher
189+
->expects($this->exactly(2))
190+
->method('dispatchTyped')
191+
->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
192+
return match(++$operation) {
193+
1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/asd/',
194+
2 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/asd/',
195+
default => false,
196+
};
197+
}));
198+
173199
$user = $this->userManager->get('u1');
174200

175201
[$storage] = $this->getStorage(10);
@@ -189,6 +215,19 @@ public function testRemoveMounts(): void {
189215
}
190216

191217
public function testChangeMounts(): void {
218+
$operation = 0;
219+
$this->eventDispatcher
220+
->expects($this->exactly(3))
221+
->method('dispatchTyped')
222+
->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
223+
return match(++$operation) {
224+
1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/bar/',
225+
2 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
226+
3 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/bar/',
227+
default => false,
228+
};
229+
}));
230+
192231
$user = $this->userManager->get('u1');
193232

194233
[$storage] = $this->getStorage(10);
@@ -212,6 +251,18 @@ public function testChangeMounts(): void {
212251
}
213252

214253
public function testChangeMountId(): void {
254+
$operation = 0;
255+
$this->eventDispatcher
256+
->expects($this->exactly(2))
257+
->method('dispatchTyped')
258+
->with($this->callback(function (UserMountAddedEvent|UserMountUpdatedEvent $event) use (&$operation) {
259+
return match(++$operation) {
260+
1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
261+
2 => $event instanceof UserMountUpdatedEvent && $event->oldMountPoint->getMountId() === null && $event->newMountPoint->getMountId() === 1,
262+
default => false,
263+
};
264+
}));
265+
215266
$user = $this->userManager->get('u1');
216267

217268
[$storage] = $this->getStorage(10);

0 commit comments

Comments
 (0)