Skip to content

Commit d2ed18f

Browse files
committed
fix(files_sharing): skip unresolvable share recipients
Assisted-by: ClaudeCode:claude-opus-4-8 Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
1 parent e8afe36 commit d2ed18f

2 files changed

Lines changed: 40 additions & 1 deletion

File tree

apps/files_sharing/lib/Listener/SharesUpdatedListener.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
use OCP\Share\Events\ShareMovedEvent;
2727
use OCP\Share\Events\ShareTransferredEvent;
2828
use OCP\Share\IManager;
29+
use OCP\User\Exceptions\UserNotFoundException;
2930
use Psr\Clock\ClockInterface;
3031
use Psr\Log\LoggerInterface;
3132

@@ -135,7 +136,17 @@ private function markOrRun(IUser $user, callable $callback): void {
135136
$elapsed = $now - $this->firstRun;
136137

137138
if ($this->cutOffMarkTime === -1.0 || $elapsed < $this->cutOffMarkTime) {
138-
$callback();
139+
try {
140+
$callback();
141+
} catch (UserNotFoundException $e) {
142+
// A share recipient may reference a user id that no backend can resolve anymore
143+
// (e.g. with LazyUser::getUID()) - like remnant / incorrectly removed user.
144+
// Skip this recipient instead of aborting the share operation.
145+
$this->logger->warning(
146+
'Skipping share mount update for unresolvable user ' . $user->getUID(),
147+
['app' => Application::APP_ID, 'exception' => $e],
148+
);
149+
}
139150
} else {
140151
$this->markUserForRefresh($user);
141152
}

apps/files_sharing/tests/SharesUpdatedListenerTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use OCP\Share\Events\ShareCreatedEvent;
2020
use OCP\Share\IManager;
2121
use OCP\Share\IShare;
22+
use OCP\User\Exceptions\UserNotFoundException;
2223
use PHPUnit\Framework\Attributes\DataProvider;
2324
use PHPUnit\Framework\MockObject\MockObject;
2425
use Psr\Clock\ClockInterface;
@@ -117,6 +118,33 @@ public function testShareAddedFilterOwner() {
117118
$this->sharesUpdatedListener->handle($event);
118119
}
119120

121+
public function testShareAddedSkipsUnresolvableUser(): void {
122+
$share = $this->createMock(IShare::class);
123+
$user1 = $this->createUser('user1', '');
124+
$user2 = $this->createUser('user2', '');
125+
126+
$this->manager->method('getUsersForShare')
127+
->willReturn([$user1, $user2]);
128+
129+
$event = new ShareCreatedEvent($share);
130+
131+
// user1 is an orphaned recipient that no backend can resolve
132+
$this->shareRecipientUpdater
133+
->expects($this->exactly(2))
134+
->method('updateForAddedShare')
135+
->willReturnCallback(function (IUser $user) use ($user1): void {
136+
if ($user === $user1) {
137+
throw new UserNotFoundException('Backends provided no user object');
138+
}
139+
});
140+
141+
// the failure is logged, not thrown
142+
$this->logger->expects($this->once())->method('warning');
143+
144+
// must not throw: user2 is still processed
145+
$this->sharesUpdatedListener->handle($event);
146+
}
147+
120148
public function testShareAccessUpdated() {
121149
$user1 = $this->createUser('user1', '');
122150
$user2 = $this->createUser('user2', '');

0 commit comments

Comments
 (0)