diff --git a/apps/files/lib/Service/OwnershipTransferService.php b/apps/files/lib/Service/OwnershipTransferService.php index e4a4e8f595aef..581d5a1294801 100644 --- a/apps/files/lib/Service/OwnershipTransferService.php +++ b/apps/files/lib/Service/OwnershipTransferService.php @@ -18,6 +18,7 @@ use OCA\Files\Exception\TransferOwnershipException; use OCA\Files_External\Config\ConfigAdapter; use OCP\Encryption\IManager as IEncryptionManager; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IHomeMountProvider; use OCP\Files\Config\IUserMountCache; use OCP\Files\File; @@ -30,6 +31,7 @@ use OCP\IUserManager; use OCP\L10N\IFactory; use OCP\Server; +use OCP\Share\Events\ShareTransferredEvent; use OCP\Share\IManager as IShareManager; use OCP\Share\IShare; use Symfony\Component\Console\Helper\ProgressBar; @@ -52,6 +54,7 @@ public function __construct( private IUserManager $userManager, private IFactory $l10nFactory, private IRootFolder $rootFolder, + private IEventDispatcher $eventDispatcher, ) { } @@ -544,6 +547,7 @@ private function restoreShares( } catch (\Throwable $e) { $output->writeln('Could not restore share with id ' . $share->getId() . ':' . $e->getMessage() . ' : ' . $e->getTraceAsString() . ''); } + $this->eventDispatcher->dispatchTyped(new ShareTransferredEvent($share)); $progress->advance(); } $progress->finish(); diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index 4f0848b60bd33..da4984d378533 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -48,7 +48,6 @@ use OCP\Files\Events\BeforeDirectFileDownloadEvent; use OCP\Files\Events\BeforeZipCreatedEvent; use OCP\Files\Events\Node\BeforeNodeReadEvent; -use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Group\Events\GroupChangedEvent; use OCP\Group\Events\GroupDeletedEvent; use OCP\Group\Events\UserAddedEvent; @@ -57,6 +56,7 @@ use OCP\IGroup; use OCP\Share\Events\BeforeShareDeletedEvent; use OCP\Share\Events\ShareCreatedEvent; +use OCP\Share\Events\ShareTransferredEvent; use OCP\User\Events\UserChangedEvent; use OCP\User\Events\UserDeletedEvent; use OCP\Util; @@ -117,10 +117,10 @@ function () use ($c) { // Update mounts $context->registerEventListener(ShareCreatedEvent::class, SharesUpdatedListener::class); $context->registerEventListener(BeforeShareDeletedEvent::class, SharesUpdatedListener::class); + $context->registerEventListener(ShareTransferredEvent::class, SharesUpdatedListener::class); $context->registerEventListener(UserAddedEvent::class, SharesUpdatedListener::class); $context->registerEventListener(UserRemovedEvent::class, SharesUpdatedListener::class); $context->registerEventListener(UserShareAccessUpdatedEvent::class, SharesUpdatedListener::class); - $context->registerEventListener(FilesystemTornDownEvent::class, SharesUpdatedListener::class); $context->registerConfigLexicon(ConfigLexicon::class); } diff --git a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php index b7b85689f8ad7..9cbea36dbaa56 100644 --- a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php +++ b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php @@ -11,73 +11,81 @@ use OCA\Files_Sharing\Event\UserShareAccessUpdatedEvent; use OCA\Files_Sharing\MountProvider; use OCA\Files_Sharing\ShareTargetValidator; -use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; -use OCP\Files\Events\Node\FilesystemTornDownEvent; +use OCP\Files\Storage\IStorageFactory; use OCP\Group\Events\UserAddedEvent; use OCP\Group\Events\UserRemovedEvent; use OCP\IUser; use OCP\Share\Events\BeforeShareDeletedEvent; use OCP\Share\Events\ShareCreatedEvent; +use OCP\Share\Events\ShareTransferredEvent; use OCP\Share\IManager; /** * Listen to various events that can change what shares a user has access to * - * @template-implements IEventListener + * @template-implements IEventListener */ class SharesUpdatedListener implements IEventListener { - private CappedMemoryCache $updatedUsers; - public function __construct( private readonly IManager $shareManager, private readonly IUserMountCache $userMountCache, private readonly MountProvider $shareMountProvider, private readonly ShareTargetValidator $shareTargetValidator, + private readonly IStorageFactory $storageFactory, ) { - $this->updatedUsers = new CappedMemoryCache(); } public function handle(Event $event): void { - if ($event instanceof FilesystemTornDownEvent) { - $this->updatedUsers = new CappedMemoryCache(); - } if ($event instanceof UserShareAccessUpdatedEvent) { foreach ($event->getUsers() as $user) { - $this->updateForUser($user); + $this->updateForUser($user, true); } } if ($event instanceof UserAddedEvent || $event instanceof UserRemovedEvent) { - $this->updateForUser($event->getUser()); + $this->updateForUser($event->getUser(), true); } - if ($event instanceof ShareCreatedEvent || $event instanceof BeforeShareDeletedEvent) { + if ( + $event instanceof ShareCreatedEvent || + $event instanceof ShareTransferredEvent + ) { foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) { - $this->updateForUser($user); + $this->updateForUser($user, true); } } - } - - private function updateForUser(IUser $user): void { - if (isset($this->updatedUsers[$user->getUID()])) { - return; + if ($event instanceof BeforeShareDeletedEvent) { + foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) { + $this->updateForUser($user, false, [$event->getShare()]); + } } - $this->updatedUsers[$user->getUID()] = true; + } + private function updateForUser(IUser $user, bool $verifyMountPoints, array $ignoreShares = []): void { $cachedMounts = $this->userMountCache->getMountsForUser($user); + $shareMounts = array_filter($cachedMounts, fn (ICachedMountInfo $mount) => $mount->getMountProvider() === MountProvider::class); $mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts); $mountsByPath = array_combine($mountPoints, $cachedMounts); - $shares = $this->shareMountProvider->getSuperSharesForUser($user); + $shares = $this->shareMountProvider->getSuperSharesForUser($user, $ignoreShares); + $mountsChanged = count($shares) !== count($shareMounts); foreach ($shares as &$share) { [$parentShare, $groupedShares] = $share; $mountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/'; $mountKey = $parentShare->getNodeId() . '::' . $mountPoint; if (!isset($cachedMounts[$mountKey])) { - $this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares); + $mountsChanged = true; + if ($verifyMountPoints) { + $this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares); + } } } + + if ($mountsChanged) { + $newMounts = $this->shareMountProvider->getMountsFromSuperShares($user, $shares, $this->storageFactory); + $this->userMountCache->registerMounts($user, $newMounts, [MountProvider::class]); + } } } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index e9575dbac26c3..befb4fd0603a7 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -13,6 +13,7 @@ use OCA\Files_Sharing\Event\ShareMountedEvent; use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\IAuthoritativeMountProvider; use OCP\Files\Config\IMountProvider; use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Mount\IMountManager; @@ -28,7 +29,7 @@ use function count; -class MountProvider implements IMountProvider, IPartialMountProvider { +class MountProvider implements IMountProvider, IAuthoritativeMountProvider, IPartialMountProvider { /** * @param IConfig $config * @param IManager $shareManager @@ -57,9 +58,10 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) { /** * @param IUser $user + * @param list $excludeShares * @return list}> Tuple of [superShare, groupedShares] */ - public function getSuperSharesForUser(IUser $user): array { + public function getSuperSharesForUser(IUser $user, array $excludeShares = []): array { $userId = $user->getUID(); $shares = $this->mergeIterables( $this->shareManager->getSharedWith($userId, IShare::TYPE_USER, null, -1), @@ -69,7 +71,8 @@ public function getSuperSharesForUser(IUser $user): array { $this->shareManager->getSharedWith($userId, IShare::TYPE_DECK, null, -1), ); - $shares = $this->filterShares($shares, $userId); + $excludeShareIds = array_map(fn (IShare $share) => $share->getFullId(), $excludeShares); + $shares = $this->filterShares($shares, $userId, $excludeShareIds); return $this->buildSuperShares($shares, $user); } @@ -340,14 +343,16 @@ public function getMountsFromSuperShares( * user has no permissions. * * @param iterable $shares + * @param list $excludeShareIds * @return iterable */ - private function filterShares(iterable $shares, string $userId): iterable { + private function filterShares(iterable $shares, string $userId, array $excludeShareIds = []): iterable { foreach ($shares as $share) { if ( $share->getPermissions() > 0 && $share->getShareOwner() !== $userId && $share->getSharedBy() !== $userId + && !in_array($share->getFullId(), $excludeShareIds) ) { yield $share; } diff --git a/lib/public/Share/Events/ShareTransferredEvent.php b/lib/public/Share/Events/ShareTransferredEvent.php new file mode 100644 index 0000000000000..d5964b780b156 --- /dev/null +++ b/lib/public/Share/Events/ShareTransferredEvent.php @@ -0,0 +1,33 @@ +share; + } +}