diff --git a/apps/files_sharing/composer/composer/autoload_classmap.php b/apps/files_sharing/composer/composer/autoload_classmap.php index dda5b5c7f7728..99ac6c7ec8664 100644 --- a/apps/files_sharing/composer/composer/autoload_classmap.php +++ b/apps/files_sharing/composer/composer/autoload_classmap.php @@ -63,11 +63,15 @@ 'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => $baseDir . '/../lib/Listener/BeforeDirectFileDownloadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeNodeReadListener' => $baseDir . '/../lib/Listener/BeforeNodeReadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => $baseDir . '/../lib/Listener/BeforeZipCreatedListener.php', + 'OCA\\Files_Sharing\\Listener\\CircleListenerBase' => $baseDir . '/../lib/Listener/CircleListenerBase.php', 'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php', 'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => $baseDir . '/../lib/Listener/LoadPublicFileRequestAuthListener.php', 'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files_Sharing\\Listener\\MemberAddedToCircleListener' => $baseDir . '/../lib/Listener/MemberAddedToCircleListener.php', + 'OCA\\Files_Sharing\\Listener\\MemberRemovedFromCircleListener' => $baseDir . '/../lib/Listener/MemberRemovedFromCircleListener.php', 'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => $baseDir . '/../lib/Listener/ShareInteractionListener.php', 'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => $baseDir . '/../lib/Listener/UserAddedToGroupListener.php', + 'OCA\\Files_Sharing\\Listener\\UserRemovedFromGroupListener' => $baseDir . '/../lib/Listener/UserRemovedFromGroupListener.php', 'OCA\\Files_Sharing\\Listener\\UserShareAcceptanceListener' => $baseDir . '/../lib/Listener/UserShareAcceptanceListener.php', 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => $baseDir . '/../lib/Middleware/OCSShareAPIMiddleware.php', 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => $baseDir . '/../lib/Middleware/ShareInfoMiddleware.php', diff --git a/apps/files_sharing/composer/composer/autoload_static.php b/apps/files_sharing/composer/composer/autoload_static.php index 195b4f0583689..28442cda4f8e9 100644 --- a/apps/files_sharing/composer/composer/autoload_static.php +++ b/apps/files_sharing/composer/composer/autoload_static.php @@ -78,11 +78,15 @@ class ComposerStaticInitFiles_Sharing 'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeDirectFileDownloadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeNodeReadListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeNodeReadListener.php', 'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeZipCreatedListener.php', + 'OCA\\Files_Sharing\\Listener\\CircleListenerBase' => __DIR__ . '/..' . '/../lib/Listener/CircleListenerBase.php', 'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php', 'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => __DIR__ . '/..' . '/../lib/Listener/LoadPublicFileRequestAuthListener.php', 'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php', + 'OCA\\Files_Sharing\\Listener\\MemberAddedToCircleListener' => __DIR__ . '/..' . '/../lib/Listener/MemberAddedToCircleListener.php', + 'OCA\\Files_Sharing\\Listener\\MemberRemovedFromCircleListener' => __DIR__ . '/..' . '/../lib/Listener/MemberRemovedFromCircleListener.php', 'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => __DIR__ . '/..' . '/../lib/Listener/ShareInteractionListener.php', 'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => __DIR__ . '/..' . '/../lib/Listener/UserAddedToGroupListener.php', + 'OCA\\Files_Sharing\\Listener\\UserRemovedFromGroupListener' => __DIR__ . '/..' . '/../lib/Listener/UserRemovedFromGroupListener.php', 'OCA\\Files_Sharing\\Listener\\UserShareAcceptanceListener' => __DIR__ . '/..' . '/../lib/Listener/UserShareAcceptanceListener.php', 'OCA\\Files_Sharing\\Middleware\\OCSShareAPIMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/OCSShareAPIMiddleware.php', 'OCA\\Files_Sharing\\Middleware\\ShareInfoMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/ShareInfoMiddleware.php', diff --git a/apps/files_sharing/lib/AppInfo/Application.php b/apps/files_sharing/lib/AppInfo/Application.php index 8ddb3afaf33aa..fb15bdacb172c 100644 --- a/apps/files_sharing/lib/AppInfo/Application.php +++ b/apps/files_sharing/lib/AppInfo/Application.php @@ -10,6 +10,8 @@ use OC\Group\DisplayNameCache as GroupDisplayNameCache; use OC\Share\Share; use OC\User\DisplayNameCache; +use OCA\Circles\Events\CircleMemberAddedEvent; +use OCA\Circles\Events\CircleMemberRemovedEvent; use OCA\Files\Event\LoadAdditionalScriptsEvent; use OCA\Files\Event\LoadSidebar; use OCA\Files_Sharing\Capabilities; @@ -23,8 +25,11 @@ use OCA\Files_Sharing\Listener\LoadAdditionalListener; use OCA\Files_Sharing\Listener\LoadPublicFileRequestAuthListener; use OCA\Files_Sharing\Listener\LoadSidebarListener; +use OCA\Files_Sharing\Listener\MemberAddedToCircleListener; +use OCA\Files_Sharing\Listener\MemberRemovedFromCircleListener; use OCA\Files_Sharing\Listener\ShareInteractionListener; use OCA\Files_Sharing\Listener\UserAddedToGroupListener; +use OCA\Files_Sharing\Listener\UserRemovedFromGroupListener; use OCA\Files_Sharing\Listener\UserShareAcceptanceListener; use OCA\Files_Sharing\Middleware\OCSShareAPIMiddleware; use OCA\Files_Sharing\Middleware\ShareInfoMiddleware; @@ -49,6 +54,7 @@ use OCP\Group\Events\GroupChangedEvent; use OCP\Group\Events\GroupDeletedEvent; use OCP\Group\Events\UserAddedEvent; +use OCP\Group\Events\UserRemovedEvent; use OCP\IDBConnection; use OCP\IGroup; use OCP\Share\Events\ShareCreatedEvent; @@ -97,6 +103,9 @@ function () use ($c) { $context->registerEventListener(ShareCreatedEvent::class, ShareInteractionListener::class); $context->registerEventListener(ShareCreatedEvent::class, UserShareAcceptanceListener::class); $context->registerEventListener(UserAddedEvent::class, UserAddedToGroupListener::class); + $context->registerEventListener(UserRemovedEvent::class, UserRemovedFromGroupListener::class); + $context->registerEventListener(CircleMemberAddedEvent::class, MemberAddedToCircleListener::class); + $context->registerEventListener(CircleMemberRemovedEvent::class, MemberRemovedFromCircleListener::class); // Publish activity for public download $context->registerEventListener(BeforeNodeReadEvent::class, BeforeNodeReadListener::class); diff --git a/apps/files_sharing/lib/Listener/CircleListenerBase.php b/apps/files_sharing/lib/Listener/CircleListenerBase.php new file mode 100644 index 0000000000000..000254c6d5800 --- /dev/null +++ b/apps/files_sharing/lib/Listener/CircleListenerBase.php @@ -0,0 +1,56 @@ + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\Files_Sharing\Listener; + +use OC\User\LazyUser; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Member; +use OCP\IUser; +use OCP\IUserManager; +use Psr\Log\LoggerInterface; + +class CircleListenerBase { + public function __construct( + private readonly IUserManager $userManager, + ) { + } + + + /** + * @return \Iterator + */ + protected function usersFromMember(Member $member): \Iterator { + if ($member->getUserType() === Member::TYPE_CIRCLE) { + $members = $member->getBasedOn()->getInheritedMembers(); + } else { + $members = [$member]; + } + + foreach ($members as $member) { + if ($member->getUserType() === Member::TYPE_USER) { + yield $member->getUserId() => new LazyUser($member->getUserId(), $this->userManager); + } elseif ($member->getUserType() === Member::TYPE_GROUP) { + // todo + } + } + } + + /** + * @return \Iterator + */ + protected function usersFromCircle(Circle $circle): \Iterator { + foreach ($circle->getInheritedMembers() as $member) { + if ($member->getUserType() === Member::TYPE_USER) { + yield $member->getUserId() => new LazyUser($member->getUserId(), $this->userManager); + } elseif ($member->getUserType() === Member::TYPE_GROUP) { + // todo + } + } + } +} diff --git a/apps/files_sharing/lib/Listener/GroupListenerBase.php b/apps/files_sharing/lib/Listener/GroupListenerBase.php new file mode 100644 index 0000000000000..cd1c53614d3ad --- /dev/null +++ b/apps/files_sharing/lib/Listener/GroupListenerBase.php @@ -0,0 +1,39 @@ + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\Files_Sharing\Listener; + +use OCA\Circles\Db\CircleRequest; +use OCA\Circles\Model\Circle; +use OCA\Circles\Model\Member; +use OCA\Circles\Model\Probes\CircleProbe; + +class GroupListenerBase { + private function getGroupCircle(CircleRequest $circleRequest, string $groupId): Circle { + $circle = new Circle(); + $circle->setName('group:' . $groupId) + ->setConfig(Circle::CFG_SYSTEM | Circle::CFG_NO_OWNER | Circle::CFG_HIDDEN) + ->setSource(Member::TYPE_GROUP); + return $circleRequest->searchCircle($circle); + } + + /** + * @return Circle[] + */ + protected function getCirclesForGroup(CircleRequest $circleRequest, string $groupId): array { + $groupCircle = $this->getGroupCircle($circleRequest, $groupId); + + $filterMember = new Member(); + $filterMember->setSingleId($groupCircle->getSingleId()); + $probe = new CircleProbe(); + $probe->filterHiddenCircles() + ->filterBackendCircles() + ->setFilterMember($filterMember); + return $circleRequest->getCircles(null, $probe); + } +} diff --git a/apps/files_sharing/lib/Listener/MemberAddedToCircleListener.php b/apps/files_sharing/lib/Listener/MemberAddedToCircleListener.php new file mode 100644 index 0000000000000..7331c98dde5a5 --- /dev/null +++ b/apps/files_sharing/lib/Listener/MemberAddedToCircleListener.php @@ -0,0 +1,57 @@ + */ +class MemberAddedToCircleListener extends CircleListenerBase implements IEventListener { + + public function __construct( + private readonly IManager $shareManager, + private readonly IEventDispatcher $eventDispatcher, + private readonly IUserManager $userManager, + ) { + parent::__construct($this->userManager); + } + + public function handle(Event $event): void { + if (!($event instanceof CircleMemberAddedEvent)) { + return; + } + + $users = $this->usersFromMember($event->getMember()); + $circle = $event->getCircle(); + + $shares = null; + foreach ($users as $user) { + if ($shares === null) { + // we only need to get the shares for one user, the shares we're looking for are common between all users + // todo: add a way to get shares by circle id + $shares = $this->shareManager->getSharedWith($user->getUID(), IShare::TYPE_CIRCLE, null, -1); + } + + foreach ($shares as $share) { + // If this is not the new circle we can skip it + if ($share->getSharedWith() !== $circle->getSingleId()) { + continue; + } + + $this->eventDispatcher->dispatchTyped(new UserAddedToShareEvent($share, $user)); + } + } + } +} diff --git a/apps/files_sharing/lib/Listener/MemberRemovedFromCircleListener.php b/apps/files_sharing/lib/Listener/MemberRemovedFromCircleListener.php new file mode 100644 index 0000000000000..077ea5f1afd8c --- /dev/null +++ b/apps/files_sharing/lib/Listener/MemberRemovedFromCircleListener.php @@ -0,0 +1,63 @@ + */ +class MemberRemovedFromCircleListener extends CircleListenerBase implements IEventListener { + + public function __construct( + private readonly IManager $shareManager, + private readonly IEventDispatcher $eventDispatcher, + private readonly IUserManager $userManager, + ) { + parent::__construct($this->userManager); + } + + public function handle(Event $event): void { + if (!($event instanceof CircleMemberRemovedEvent)) { + return; + } + + $circle = $event->getCircle(); + + $circleMembers = iterator_to_array($this->usersFromCircle($circle)); + // todo: add a way to get shares by circle id + if (count($circleMembers)) { + $user = current($circleMembers); + // get the shares from a user still in the circle + $shares = $this->shareManager->getSharedWith($user->getUID(), IShare::TYPE_CIRCLE, null, -1); + } else { + // if nobody is in the circle anymore we current have to go through all shares + // todo: add a way to get shares by group id + $shares = $this->shareManager->getAllShares(); + } + + foreach ($shares as $share) { + // If this is not the new group we can skip it + if ($share->getShareType() === IShare::TYPE_CIRCLE && $share->getSharedWith() !== $circle->getSingleId()) { + continue; + } + + foreach ($this->usersFromMember($event->getMember()) as $user) { + if (!isset($circleMembers[$user->getUID()])) { + $this->eventDispatcher->dispatchTyped(new UserRemovedFromShareEvent($share, $user)); + } + } + } + } +} diff --git a/apps/files_sharing/lib/Listener/UserAddedToGroupListener.php b/apps/files_sharing/lib/Listener/UserAddedToGroupListener.php index 281c96ca5e7c0..f79a3d5bdebcd 100644 --- a/apps/files_sharing/lib/Listener/UserAddedToGroupListener.php +++ b/apps/files_sharing/lib/Listener/UserAddedToGroupListener.php @@ -6,22 +6,31 @@ * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors * SPDX-License-Identifier: AGPL-3.0-or-later */ + namespace OCA\Files_Sharing\Listener; +use OCA\Circles\Db\CircleRequest; +use OCA\Circles\Model\Circle; use OCA\Files_Sharing\AppInfo\Application; +use OCP\App\IAppManager; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; use OCP\Group\Events\UserAddedEvent; use OCP\IConfig; +use OCP\Share\Events\UserAddedToShareEvent; use OCP\Share\IManager; use OCP\Share\IShare; +use Psr\Container\ContainerInterface; /** @template-implements IEventListener */ -class UserAddedToGroupListener implements IEventListener { - +class UserAddedToGroupListener extends GroupListenerBase implements IEventListener { public function __construct( - private IManager $shareManager, - private IConfig $config, + private readonly IManager $shareManager, + private readonly IConfig $config, + private readonly IEventDispatcher $eventDispatcher, + private readonly IAppManager $appManager, + private readonly ContainerInterface $container, ) { } @@ -33,22 +42,44 @@ public function handle(Event $event): void { $user = $event->getUser(); $group = $event->getGroup(); - // This user doesn't have autoaccept so we can skip it all - if (!$this->hasAutoAccept($user->getUID())) { - return; - } + // Get all group shares this user has access too now to filter later + $groupShares = $this->shareManager->getSharedWith($user->getUID(), IShare::TYPE_GROUP, null, -1); - // Get all group shares this user has access to now to filter later - $shares = $this->shareManager->getSharedWith($user->getUID(), IShare::TYPE_GROUP, null, -1); - - foreach ($shares as $share) { + foreach ($groupShares as $share) { // If this is not the new group we can skip it if ($share->getSharedWith() !== $group->getGID()) { continue; } // Accept the share if needed - $this->shareManager->acceptShare($share, $user->getUID()); + if ($this->hasAutoAccept($user->getUID())) { + $this->shareManager->acceptShare($share, $user->getUID()); + } + + $this->eventDispatcher->dispatchTyped(new UserAddedToShareEvent($share, $user)); + } + + if ($this->appManager->isAppLoaded('circles')) { + // Get all circle shares this user has access too now to filter later + $circleShares = $this->shareManager->getSharedWith($user->getUID(), IShare::TYPE_CIRCLE, null, -1); + if (count($circleShares) === 0) { + return; + } + + /** @var CircleRequest $circlesRequest */ + $circlesRequest = $this->container->get(CircleRequest::class); + $circles = $this->getCirclesForGroup($circlesRequest, $group->getGID()); + $circleIds = array_map(fn (Circle $circle) => $circle->getSingleId(), $circles); + + foreach ($circleShares as $share) { + if (!in_array($share->getSharedWith(), $circleIds)) { + continue; + } + // todo: detect if this share is new for the user because it only has access trough the new group + // or if the user already had access before + + $this->eventDispatcher->dispatchTyped(new UserAddedToShareEvent($share, $user)); + } } } diff --git a/apps/files_sharing/lib/Listener/UserRemovedFromGroupListener.php b/apps/files_sharing/lib/Listener/UserRemovedFromGroupListener.php new file mode 100644 index 0000000000000..d2b1dde31207a --- /dev/null +++ b/apps/files_sharing/lib/Listener/UserRemovedFromGroupListener.php @@ -0,0 +1,56 @@ + */ +class UserRemovedFromGroupListener extends GroupListenerBase implements IEventListener { + + public function __construct( + private readonly ContainerInterface $container, + private readonly IAppManager $appManager, + private readonly IEventDispatcher $eventDispatcher, + private readonly DefaultShareProvider $shareProvider, + ) { + } + + public function handle(Event $event): void { + if (!($event instanceof UserRemovedEvent)) { + return; + } + + $user = $event->getUser(); + $group = $event->getGroup(); + + $shares = $this->shareProvider->getSharedWithGroup($group->getGID()); + + foreach ($shares as $share) { + $this->eventDispatcher->dispatchTyped(new UserRemovedFromShareEvent($share, $user)); + } + + if ($this->appManager->isAppLoaded('circles')) { + /** @var CircleRequest $circlesRequest */ + $circlesRequest = $this->container->get(CircleRequest::class); + $circles = $this->getCirclesForGroup($circlesRequest, $group->getGID()); + $circleIds = array_map(fn (Circle $circle) => $circle->getSingleId(), $circles); + + // todo: get shares by circles, see which of those the user still has access to, emit event for those that the user doesn't + } + } +} diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index c0c3111f5facb..fcccfcdc016a4 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -803,6 +803,8 @@ 'OCP\\Share\\Events\\ShareCreatedEvent' => $baseDir . '/lib/public/Share/Events/ShareCreatedEvent.php', 'OCP\\Share\\Events\\ShareDeletedEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedEvent.php', 'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => $baseDir . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php', + 'OCP\\Share\\Events\\UserAddedToShareEvent' => $baseDir . '/lib/public/Share/Events/UserAddedToShareEvent.php', + 'OCP\\Share\\Events\\UserRemovedFromShareEvent' => $baseDir . '/lib/public/Share/Events/UserRemovedFromShareEvent.php', 'OCP\\Share\\Events\\VerifyMountPointEvent' => $baseDir . '/lib/public/Share/Events/VerifyMountPointEvent.php', 'OCP\\Share\\Exceptions\\AlreadySharedException' => $baseDir . '/lib/public/Share/Exceptions/AlreadySharedException.php', 'OCP\\Share\\Exceptions\\GenericShareException' => $baseDir . '/lib/public/Share/Exceptions/GenericShareException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 4a35216a172f8..1f5d875b7eccd 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -844,6 +844,8 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Share\\Events\\ShareCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareCreatedEvent.php', 'OCP\\Share\\Events\\ShareDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedEvent.php', 'OCP\\Share\\Events\\ShareDeletedFromSelfEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/ShareDeletedFromSelfEvent.php', + 'OCP\\Share\\Events\\UserAddedToShareEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/UserAddedToShareEvent.php', + 'OCP\\Share\\Events\\UserRemovedFromShareEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/UserRemovedFromShareEvent.php', 'OCP\\Share\\Events\\VerifyMountPointEvent' => __DIR__ . '/../../..' . '/lib/public/Share/Events/VerifyMountPointEvent.php', 'OCP\\Share\\Exceptions\\AlreadySharedException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/AlreadySharedException.php', 'OCP\\Share\\Exceptions\\GenericShareException' => __DIR__ . '/../../..' . '/lib/public/Share/Exceptions/GenericShareException.php', diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 5300e6e1baad2..bd6d133ed6898 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -948,6 +948,40 @@ public function getSharedWith($userId, $shareType, $node, $limit, $offset) { return $shares; } + public function getSharedWithGroup(string $groupId): array { + $qb = $this->dbConn->getQueryBuilder(); + $qb->select('s.*', + 'f.fileid', 'f.path', 'f.permissions AS f_permissions', 'f.storage', 'f.path_hash', + 'f.parent AS f_parent', 'f.name', 'f.mimetype', 'f.mimepart', 'f.size', 'f.mtime', 'f.storage_mtime', + 'f.encrypted', 'f.unencrypted_size', 'f.etag', 'f.checksum' + ) + ->selectAlias('st.id', 'storage_string_id') + ->from('share', 's') + ->leftJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')) + ->leftJoin('f', 'storages', 'st', $qb->expr()->eq('f.storage', 'st.numeric_id')) + ->orderBy('s.id'); + + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_GROUP))) + ->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($groupId))) + ->andWhere($qb->expr()->in('item_type', $qb->createNamedParameter(['file', 'folder'], IQueryBuilder::PARAM_STR_ARRAY))); + + $shares = []; + $cursor = $qb->executeQuery(); + while ($data = $cursor->fetch()) { + if ($offset > 0) { + $offset--; + continue; + } + + if ($this->isAccessibleResult($data)) { + $share = $this->createShare($data); + $shares[$share->getId()] = $share; + } + } + $cursor->closeCursor(); + return $shares; + } + /** * Get a share by token * diff --git a/lib/public/Share/Events/UserAddedToShareEvent.php b/lib/public/Share/Events/UserAddedToShareEvent.php new file mode 100644 index 0000000000000..7f9605936d628 --- /dev/null +++ b/lib/public/Share/Events/UserAddedToShareEvent.php @@ -0,0 +1,49 @@ + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\Share\Events; + +use OCP\EventDispatcher\Event; +use OCP\IUser; +use OCP\Share\IShare; +use Psr\Log\LoggerInterface; + +/** + * A user has gained access to an existing share, for example by being added + * to a group that is receiving a share. + * + * Note that this event might be emitted as a false positive in cases where a user + * has access to a share trough multiple paths + * + * @since 33.0.0 + */ +class UserAddedToShareEvent extends Event { + /** + * @since 33.0.0 + */ + public function __construct( + private readonly IShare $share, + private readonly IUser $user, + ) { + parent::__construct(); + } + + /** + * @since 33.0.0 + */ + public function getShare(): IShare { + return $this->share; + } + + /** + * @since 33.0.0 + */ + public function getUser(): IUser { + return $this->user; + } +} diff --git a/lib/public/Share/Events/UserRemovedFromShareEvent.php b/lib/public/Share/Events/UserRemovedFromShareEvent.php new file mode 100644 index 0000000000000..d7d57cb8e1dca --- /dev/null +++ b/lib/public/Share/Events/UserRemovedFromShareEvent.php @@ -0,0 +1,47 @@ + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCP\Share\Events; + +use OCP\EventDispatcher\Event; +use OCP\IUser; +use OCP\Share\IShare; +use Psr\Log\LoggerInterface; + +/** + * A user has lost access to an existing share, for example by being removed + * from a group that is receiving a share. + * + * @since 33.0.0 + */ +class UserRemovedFromShareEvent extends Event { + /** + * @since 33.0.0 + */ + public function __construct( + private readonly IShare $share, + private readonly IUser $user, + ) { + parent::__construct(); + \OC::$server->get(LoggerInterface::class)->error("{$this->user->getUID()} removed from share"); + } + + /** + * @since 33.0.0 + */ + public function getShare(): IShare { + return $this->share; + } + + /** + * @since 33.0.0 + */ + public function getUser(): IUser { + return $this->user; + } +}