diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/Files/Cache/QuerySearchHelper.php | 65 | ||||
-rw-r--r-- | lib/private/Files/Cache/SearchBuilder.php | 17 | ||||
-rw-r--r-- | lib/private/Files/Node/Folder.php | 5 | ||||
-rw-r--r-- | lib/private/Files/Node/LazyFolder.php | 4 | ||||
-rw-r--r-- | lib/private/SystemTag/SystemTagManager.php | 9 | ||||
-rw-r--r-- | lib/private/SystemTag/SystemTagObjectMapper.php | 1 | ||||
-rw-r--r-- | lib/public/Files/Folder.php | 10 | ||||
-rw-r--r-- | lib/public/SystemTag/ISystemTagManager.php | 5 |
8 files changed, 80 insertions, 36 deletions
diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php index 75e203d5fd9..15c089a0f11 100644 --- a/lib/private/Files/Cache/QuerySearchHelper.php +++ b/lib/private/Files/Cache/QuerySearchHelper.php @@ -38,6 +38,8 @@ use OCP\Files\Mount\IMountPoint; use OCP\Files\Search\ISearchBinaryOperator; use OCP\Files\Search\ISearchQuery; use OCP\IDBConnection; +use OCP\IGroupManager; +use OCP\IUser; use Psr\Log\LoggerInterface; class QuerySearchHelper { @@ -52,6 +54,7 @@ class QuerySearchHelper { private $searchBuilder; /** @var QueryOptimizer */ private $queryOptimizer; + private IGroupManager $groupManager; public function __construct( IMimeTypeLoader $mimetypeLoader, @@ -59,7 +62,8 @@ class QuerySearchHelper { SystemConfig $systemConfig, LoggerInterface $logger, SearchBuilder $searchBuilder, - QueryOptimizer $queryOptimizer + QueryOptimizer $queryOptimizer, + IGroupManager $groupManager, ) { $this->mimetypeLoader = $mimetypeLoader; $this->connection = $connection; @@ -67,6 +71,7 @@ class QuerySearchHelper { $this->logger = $logger; $this->searchBuilder = $searchBuilder; $this->queryOptimizer = $queryOptimizer; + $this->groupManager = $groupManager; } protected function getQueryBuilder() { @@ -116,6 +121,29 @@ class QuerySearchHelper { return $tags; } + protected function equipQueryForSystemTags(CacheQueryBuilder $query, IUser $user): void { + $query->leftJoin('file', 'systemtag_object_mapping', 'systemtagmap', $query->expr()->andX( + $query->expr()->eq('file.fileid', $query->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)), + $query->expr()->eq('systemtagmap.objecttype', $query->createNamedParameter('files')) + )); + $on = $query->expr()->andX($query->expr()->eq('systemtag.id', 'systemtagmap.systemtagid')); + if (!$this->groupManager->isAdmin($user->getUID())) { + $on->add($query->expr()->eq('systemtag.visibility', $query->createNamedParameter(true))); + } + $query->leftJoin('systemtagmap', 'systemtag', 'systemtag', $on); + } + + protected function equipQueryForDavTags(CacheQueryBuilder $query, IUser $user): void { + $query + ->leftJoin('file', 'vcategory_to_object', 'tagmap', $query->expr()->eq('file.fileid', 'tagmap.objid')) + ->leftJoin('tagmap', 'vcategory', 'tag', $query->expr()->andX( + $query->expr()->eq('tagmap.type', 'tag.type'), + $query->expr()->eq('tagmap.categoryid', 'tag.id'), + $query->expr()->eq('tag.type', $query->createNamedParameter('files')), + $query->expr()->eq('tag.uid', $query->createNamedParameter($user->getUID())) + )); + } + /** * Perform a file system search in multiple caches * @@ -146,27 +174,12 @@ class QuerySearchHelper { $query = $builder->selectFileCache('file', false); - if ($this->searchBuilder->shouldJoinTags($searchQuery->getSearchOperation())) { - $user = $searchQuery->getUser(); - if ($user === null) { - throw new \InvalidArgumentException("Searching by tag requires the user to be set in the query"); - } - $query - ->leftJoin('file', 'vcategory_to_object', 'tagmap', $builder->expr()->eq('file.fileid', 'tagmap.objid')) - ->leftJoin('tagmap', 'vcategory', 'tag', $builder->expr()->andX( - $builder->expr()->eq('tagmap.type', 'tag.type'), - $builder->expr()->eq('tagmap.categoryid', 'tag.id'), - $builder->expr()->eq('tag.type', $builder->createNamedParameter('files')), - $builder->expr()->eq('tag.uid', $builder->createNamedParameter($user->getUID())) - )) - ->leftJoin('file', 'systemtag_object_mapping', 'systemtagmap', $builder->expr()->andX( - $builder->expr()->eq('file.fileid', $builder->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)), - $builder->expr()->eq('systemtagmap.objecttype', $builder->createNamedParameter('files')) - )) - ->leftJoin('systemtagmap', 'systemtag', 'systemtag', $builder->expr()->andX( - $builder->expr()->eq('systemtag.id', 'systemtagmap.systemtagid'), - $builder->expr()->eq('systemtag.visibility', $builder->createNamedParameter(true)) - )); + $requestedFields = $this->searchBuilder->extractRequestedFields($searchQuery->getSearchOperation()); + if (in_array('systemtag', $requestedFields)) { + $this->equipQueryForSystemTags($query, $this->requireUser($searchQuery)); + } + if (in_array('tagname', $requestedFields) || in_array('favorite', $requestedFields)) { + $this->equipQueryForDavTags($query, $this->requireUser($searchQuery)); } $this->applySearchConstraints($query, $searchQuery, $caches); @@ -194,6 +207,14 @@ class QuerySearchHelper { return $results; } + protected function requireUser(ISearchQuery $searchQuery): IUser { + $user = $searchQuery->getUser(); + if ($user === null) { + throw new \InvalidArgumentException("This search operation requires the user to be set in the query"); + } + return $user; + } + /** * @return list{0?: array<array-key, ICache>, 1?: array<array-key, IMountPoint>} */ diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index c9f35ccd095..b9a70bbd39b 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -69,20 +69,17 @@ class SearchBuilder { } /** - * Whether or not the tag tables should be joined to complete the search - * - * @param ISearchOperator $operator - * @return boolean + * @return string[] */ - public function shouldJoinTags(ISearchOperator $operator) { + public function extractRequestedFields(ISearchOperator $operator): array { if ($operator instanceof ISearchBinaryOperator) { - return array_reduce($operator->getArguments(), function ($shouldJoin, ISearchOperator $operator) { - return $shouldJoin || $this->shouldJoinTags($operator); - }, false); + return array_reduce($operator->getArguments(), function (array $fields, ISearchOperator $operator) { + return array_unique(array_merge($fields, $this->extractRequestedFields($operator))); + }, []); } elseif ($operator instanceof ISearchComparison) { - return $operator->getField() === 'tagname' || $operator->getField() === 'favorite' || $operator->getField() === 'systemtag'; + return [$operator->getField()]; } - return false; + return []; } /** diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index 6a009bded96..3622f336047 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -300,6 +300,11 @@ class Folder extends Node implements \OCP\Files\Folder { return $this->search($query); } + public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0): array { + $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'systemtag', $tagName), $userId, $limit, $offset); + return $this->search($query); + } + /** * @param int $id * @return \OC\Files\Node\Node[] diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php index 9f9528f69bd..d495d6f4c57 100644 --- a/lib/private/Files/Node/LazyFolder.php +++ b/lib/private/Files/Node/LazyFolder.php @@ -449,6 +449,10 @@ class LazyFolder implements Folder { return $this->__call(__FUNCTION__, func_get_args()); } + public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0) { + return $this->__call(__FUNCTION__, func_get_args()); + } + /** * @inheritDoc */ diff --git a/lib/private/SystemTag/SystemTagManager.php b/lib/private/SystemTag/SystemTagManager.php index 79c5adcf450..65046ebf000 100644 --- a/lib/private/SystemTag/SystemTagManager.php +++ b/lib/private/SystemTag/SystemTagManager.php @@ -91,7 +91,7 @@ class SystemTagManager implements ISystemTagManager { /** * {@inheritdoc} */ - public function getTagsByIds($tagIds): array { + public function getTagsByIds($tagIds, ?IUser $user = null): array { if (!\is_array($tagIds)) { $tagIds = [$tagIds]; } @@ -116,7 +116,12 @@ class SystemTagManager implements ISystemTagManager { $result = $query->execute(); while ($row = $result->fetch()) { - $tags[$row['id']] = $this->createSystemTagFromRow($row); + $tag = $this->createSystemTagFromRow($row); + if ($user && !$this->canUserSeeTag($tag, $user)) { + // if a user is given, hide invisible tags + continue; + } + $tags[$row['id']] = $tag; } $result->closeCursor(); diff --git a/lib/private/SystemTag/SystemTagObjectMapper.php b/lib/private/SystemTag/SystemTagObjectMapper.php index b61a81a1fa7..864ba3e91a8 100644 --- a/lib/private/SystemTag/SystemTagObjectMapper.php +++ b/lib/private/SystemTag/SystemTagObjectMapper.php @@ -135,6 +135,7 @@ class SystemTagObjectMapper implements ISystemTagObjectMapper { while ($row = $result->fetch()) { $objectIds[] = $row['objectid']; } + $result->closeCursor(); return $objectIds; } diff --git a/lib/public/Files/Folder.php b/lib/public/Files/Folder.php index 912c5472fac..eb81a2098ec 100644 --- a/lib/public/Files/Folder.php +++ b/lib/public/Files/Folder.php @@ -142,6 +142,16 @@ interface Folder extends Node { public function searchByTag($tag, $userId); /** + * search for files by system tag + * + * @param string|int $tag tag name + * @param string $userId user id to ensure access on returned nodes + * @return \OCP\Files\Node[] + * @since 28.0.0 + */ + public function searchBySystemTag(string $tagName, string $userId, int $limit = 0, int $offset = 0); + + /** * get a file or folder inside the folder by it's internal id * * This method could return multiple entries. For example once the file/folder diff --git a/lib/public/SystemTag/ISystemTagManager.php b/lib/public/SystemTag/ISystemTagManager.php index 1cf7263b456..0f5c373c49f 100644 --- a/lib/public/SystemTag/ISystemTagManager.php +++ b/lib/public/SystemTag/ISystemTagManager.php @@ -38,6 +38,7 @@ interface ISystemTagManager { * Returns the tag objects matching the given tag ids. * * @param array|string $tagIds id or array of unique ids of the tag to retrieve + * @param ?IUser $user optional user to run a visibility check against for each tag * * @return ISystemTag[] array of system tags with tag id as key * @@ -45,9 +46,9 @@ interface ISystemTagManager { * @throws TagNotFoundException if at least one given tag ids did no exist * The message contains a json_encoded array of the ids that could not be found * - * @since 9.0.0 + * @since 9.0.0, optional parameter $user added in 28.0.0 */ - public function getTagsByIds($tagIds): array; + public function getTagsByIds($tagIds, ?IUser $user = null): array; /** * Returns the tag object matching the given attributes. |