From cb2495a1c27aa014139f675ad3ec49e9aced164f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Thu, 22 Jun 2023 14:55:18 +0200 Subject: [PATCH 1/5] feat: Add a method to get all users with access to a file in OCP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/comments/lib/Activity/Listener.php | 19 +++------------ lib/private/Files/Config/UserMountCache.php | 26 +++++++++++++++++++++ lib/public/Files/Config/IUserMountCache.php | 9 +++++++ 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/apps/comments/lib/Activity/Listener.php b/apps/comments/lib/Activity/Listener.php index b07cb19afdab2..da5863e095309 100644 --- a/apps/comments/lib/Activity/Listener.php +++ b/apps/comments/lib/Activity/Listener.php @@ -12,7 +12,6 @@ use OCP\Comments\CommentsEvent; use OCP\Files\Config\IMountProviderCollection; use OCP\Files\IRootFolder; -use OCP\Files\Node; use OCP\IUser; use OCP\IUserSession; use OCP\Share\IShareHelper; @@ -36,24 +35,12 @@ public function commentEvent(CommentsEvent $event): void { return; } - // Get all mount point owners $cache = $this->mountCollection->getMountCache(); - $mounts = $cache->getMountsForFileId((int)$event->getComment()->getObjectId()); - if (empty($mounts)) { - return; - } $users = []; - foreach ($mounts as $mount) { - $owner = $mount->getUser()->getUID(); - $ownerFolder = $this->rootFolder->getUserFolder($owner); - $nodes = $ownerFolder->getById((int)$event->getComment()->getObjectId()); - if (!empty($nodes)) { - /** @var Node $node */ - $node = array_shift($nodes); - $al = $this->shareHelper->getPathsForAccessList($node); - $users += $al['users']; - } + $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getComment()->getObjectId()); + foreach ($filesPerUser as $user => $files) { + $users[$user] = reset($files)?->getPath(); } $actor = $this->session->getUser(); diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 94da770b63f06..0d72e3a6d4f89 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -14,10 +14,14 @@ use OCP\Files\Config\ICachedMountFileInfo; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; +use OCP\Files\IRootFolder; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IDBConnection; use OCP\IUser; use OCP\IUserManager; +use OCP\Server; use Psr\Log\LoggerInterface; /** @@ -380,6 +384,28 @@ public function getMountsForFileId($fileId, $user = null) { }, $filteredMounts); } + /** + * Get all nodes that give access to a file + * + * @return array Nodes giving access to the given fileId, indexed by user ID + * @since 28.0.0 + */ + public function getReadableNodesByUserForFileId(int $fileId): array { + $mounts = $this->getMountsForFileId($fileId); + $rootFolder = Server::get(IRootFolder::class); + $result = []; + foreach ($mounts as $mount) { + if (isset($result[$mount->getUser()->getUID()])) { + continue; + } + + $userFolder = $rootFolder->getUserFolder($mount->getUser()->getUID()); + $result[$mount->getUser()->getUID()] = $userFolder->getById($fileId); + } + + return $result; + } + /** * Remove all cached mounts for a user * diff --git a/lib/public/Files/Config/IUserMountCache.php b/lib/public/Files/Config/IUserMountCache.php index a5b68ded66d15..2ec368f80ad1d 100644 --- a/lib/public/Files/Config/IUserMountCache.php +++ b/lib/public/Files/Config/IUserMountCache.php @@ -8,6 +8,7 @@ namespace OCP\Files\Config; use OCP\Files\Mount\IMountPoint; +use OCP\Files\Node; use OCP\Files\NotFoundException; use OCP\IUser; @@ -65,6 +66,14 @@ public function getMountsForRootId($rootFileId); */ public function getMountsForFileId($fileId, $user = null); + /** + * Get all cached nodes that give access to a file + * + * @return array Nodes giving access to the given fileId, indexed by user ID + * @since 28.0.0 + */ + public function getReadableNodesByUserForFileId(int $fileId): array; + /** * Remove all cached mounts for a user * From 8f0b7ce6e5ac653a9dcaa8f876ef10a1d1a2b336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 26 Jun 2023 15:54:19 +0200 Subject: [PATCH 2/5] fix: Remove /user/files prefix from paths in comment activities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/comments/lib/Activity/Listener.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/comments/lib/Activity/Listener.php b/apps/comments/lib/Activity/Listener.php index da5863e095309..fc2205c50c6c2 100644 --- a/apps/comments/lib/Activity/Listener.php +++ b/apps/comments/lib/Activity/Listener.php @@ -40,7 +40,9 @@ public function commentEvent(CommentsEvent $event): void { $users = []; $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getComment()->getObjectId()); foreach ($filesPerUser as $user => $files) { - $users[$user] = reset($files)?->getPath(); + /* Remove /user/files prefix */ + $sections = explode('/', reset($files)?->getPath() ?? '', 4); + $users[$user] = '/'.($sections[3] ?? ''); } $actor = $this->session->getUser(); From fd8c6ac9ede7b46ad1fd50f53e31b10e633b6384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Mon, 26 Jun 2023 15:54:46 +0200 Subject: [PATCH 3/5] feat: Use the new OCP method to get user with access to a file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/systemtags/lib/Activity/Listener.php | 23 ++++++++--------------- core/Command/Info/FileUtils.php | 13 +------------ 2 files changed, 9 insertions(+), 27 deletions(-) diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index 7ab00787a763f..4094760bbeef5 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -11,7 +11,6 @@ use OCP\App\IAppManager; use OCP\Files\Config\IMountProviderCollection; use OCP\Files\IRootFolder; -use OCP\Files\Node; use OCP\IConfig; use OCP\IGroup; use OCP\IGroupManager; @@ -153,22 +152,16 @@ public function mapperEvent(MapperEvent $event) { // Get all mount point owners $cache = $this->mountCollection->getMountCache(); - $mounts = $cache->getMountsForFileId($event->getObjectId()); - if (empty($mounts)) { - return; - } $users = []; - foreach ($mounts as $mount) { - $owner = $mount->getUser()->getUID(); - $ownerFolder = $this->rootFolder->getUserFolder($owner); - $nodes = $ownerFolder->getById($event->getObjectId()); - if (!empty($nodes)) { - /** @var Node $node */ - $node = array_shift($nodes); - $al = $this->shareHelper->getPathsForAccessList($node); - $users += $al['users']; - } + $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getObjectId()); + if (empty($filesPerUser)) { + return; + } + foreach ($filesPerUser as $user => $files) { + /* Remove /user/files prefix */ + $sections = explode('/', reset($files)?->getPath() ?? '', 4); + $users[$user] = '/'.($sections[3] ?? ''); } $actor = $this->session->getUser(); diff --git a/core/Command/Info/FileUtils.php b/core/Command/Info/FileUtils.php index df7dba175ba24..47f477c166aba 100644 --- a/core/Command/Info/FileUtils.php +++ b/core/Command/Info/FileUtils.php @@ -44,18 +44,7 @@ public function getFilesByUser(FileInfo $file): array { return []; } - $mounts = $this->userMountCache->getMountsForFileId($id); - $result = []; - foreach ($mounts as $mount) { - if (isset($result[$mount->getUser()->getUID()])) { - continue; - } - - $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID()); - $result[$mount->getUser()->getUID()] = $userFolder->getById($id); - } - - return $result; + return $this->userMountCache->getReadableNodesByUserForFileId($id); } /** From 8977e4eb0647224608e795265401d35f6d1b567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 27 Jun 2023 11:41:49 +0200 Subject: [PATCH 4/5] fix: Use getRelativePath for relative path in activity listeners MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Côme Chilliet --- apps/comments/lib/Activity/Listener.php | 4 +--- apps/systemtags/lib/Activity/Listener.php | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/apps/comments/lib/Activity/Listener.php b/apps/comments/lib/Activity/Listener.php index fc2205c50c6c2..5e79b5fda7348 100644 --- a/apps/comments/lib/Activity/Listener.php +++ b/apps/comments/lib/Activity/Listener.php @@ -40,9 +40,7 @@ public function commentEvent(CommentsEvent $event): void { $users = []; $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getComment()->getObjectId()); foreach ($filesPerUser as $user => $files) { - /* Remove /user/files prefix */ - $sections = explode('/', reset($files)?->getPath() ?? '', 4); - $users[$user] = '/'.($sections[3] ?? ''); + $users[$user] = $this->rootFolder->getUserFolder($user)->getRelativePath(reset($files)?->getPath() ?? ''); } $actor = $this->session->getUser(); diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index 4094760bbeef5..cfd5fefb08ded 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -159,9 +159,7 @@ public function mapperEvent(MapperEvent $event) { return; } foreach ($filesPerUser as $user => $files) { - /* Remove /user/files prefix */ - $sections = explode('/', reset($files)?->getPath() ?? '', 4); - $users[$user] = '/'.($sections[3] ?? ''); + $users[$user] = $this->rootFolder->getUserFolder($user)->getRelativePath(reset($files)?->getPath() ?? ''); } $actor = $this->session->getUser(); From c1c40ff2bbad6c9fb1b0469f3e2d4743a1fe51a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=B4me=20Chilliet?= Date: Tue, 27 Jun 2023 15:00:06 +0200 Subject: [PATCH 5/5] fix: Split in getReadablePathByUserForFileId and getReadableNodesByUserForFileId MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Optimises further and avoid duplicate code for all activity listeners Signed-off-by: Côme Chilliet --- apps/comments/lib/Activity/Listener.php | 7 ++-- apps/systemtags/lib/Activity/Listener.php | 8 ++--- lib/private/Files/Config/UserMountCache.php | 39 +++++++++++++++++++-- lib/public/Files/Config/IUserMountCache.php | 9 +++++ 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/apps/comments/lib/Activity/Listener.php b/apps/comments/lib/Activity/Listener.php index 5e79b5fda7348..939f17dcd2e66 100644 --- a/apps/comments/lib/Activity/Listener.php +++ b/apps/comments/lib/Activity/Listener.php @@ -37,10 +37,9 @@ public function commentEvent(CommentsEvent $event): void { $cache = $this->mountCollection->getMountCache(); - $users = []; - $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getComment()->getObjectId()); - foreach ($filesPerUser as $user => $files) { - $users[$user] = $this->rootFolder->getUserFolder($user)->getRelativePath(reset($files)?->getPath() ?? ''); + $users = $cache->getReadablePathByUserForFileId((int)$event->getComment()->getObjectId()); + if (empty($users)) { + return; } $actor = $this->session->getUser(); diff --git a/apps/systemtags/lib/Activity/Listener.php b/apps/systemtags/lib/Activity/Listener.php index cfd5fefb08ded..1fdad6f42c9ff 100644 --- a/apps/systemtags/lib/Activity/Listener.php +++ b/apps/systemtags/lib/Activity/Listener.php @@ -153,14 +153,10 @@ public function mapperEvent(MapperEvent $event) { // Get all mount point owners $cache = $this->mountCollection->getMountCache(); - $users = []; - $filesPerUser = $cache->getReadableNodesByUserForFileId((int)$event->getObjectId()); - if (empty($filesPerUser)) { + $users = $cache->getReadablePathByUserForFileId((int)$event->getObjectId()); + if (empty($users)) { return; } - foreach ($filesPerUser as $user => $files) { - $users[$user] = $this->rootFolder->getUserFolder($user)->getRelativePath(reset($files)?->getPath() ?? ''); - } $actor = $this->session->getUser(); if ($actor instanceof IUser) { diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php index 0d72e3a6d4f89..2445f54c56ad1 100644 --- a/lib/private/Files/Config/UserMountCache.php +++ b/lib/private/Files/Config/UserMountCache.php @@ -395,12 +395,45 @@ public function getReadableNodesByUserForFileId(int $fileId): array { $rootFolder = Server::get(IRootFolder::class); $result = []; foreach ($mounts as $mount) { - if (isset($result[$mount->getUser()->getUID()])) { + $uid = $mount->getUser()->getUID(); + if (!isset($result[$uid])) { + $result[$uid] = []; + } + + $userFolder = $rootFolder->getUserFolder($uid); + $result[$uid] = array_merge($result[$uid], $userFolder->getById($fileId)); + } + + return array_filter($result); + } + + /** + * Get all users having read access to a file, with a path they see it as. + * They may see the same file under other paths, + * to get this information use the exhaustive getReadableNodesByUserForFileId + * + * @return array Paths giving access to the given fileId, indexed by user ID + * @since 28.0.0 + */ + public function getReadablePathByUserForFileId(int $fileId): array { + $mounts = $this->getMountsForFileId($fileId); + $rootFolder = Server::get(IRootFolder::class); + $result = []; + foreach ($mounts as $mount) { + $uid = $mount->getUser()->getUID(); + if (isset($result[$uid])) { continue; } - $userFolder = $rootFolder->getUserFolder($mount->getUser()->getUID()); - $result[$mount->getUser()->getUID()] = $userFolder->getById($fileId); + $userFolder = $rootFolder->getUserFolder($uid); + $nodes = $userFolder->getById($fileId); + $node = reset($nodes); + if ($node) { + $path = $userFolder->getRelativePath($node->getPath()); + if ($path !== null) { + $result[$uid] = $path; + } + } } return $result; diff --git a/lib/public/Files/Config/IUserMountCache.php b/lib/public/Files/Config/IUserMountCache.php index 2ec368f80ad1d..5c4fcf83f4ae9 100644 --- a/lib/public/Files/Config/IUserMountCache.php +++ b/lib/public/Files/Config/IUserMountCache.php @@ -74,6 +74,15 @@ public function getMountsForFileId($fileId, $user = null); */ public function getReadableNodesByUserForFileId(int $fileId): array; + /** + * Get all users having read access to a file, with a path they see it as. + * They may see the same file under other paths, to get this information use exhaustive getReadableNodesByUserForFileId + * + * @return array Paths giving access to the given fileId, indexed by user ID + * @since 28.0.0 + */ + public function getReadablePathByUserForFileId(int $fileId): array; + /** * Remove all cached mounts for a user *