summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Schiwon <blizzz@arthur-schiwon.de>2023-04-27 22:24:16 +0200
committerArthur Schiwon <blizzz@arthur-schiwon.de>2023-05-16 12:46:37 +0200
commit2ea872d1562e77f486eb21323a2905b0585ea2f4 (patch)
tree7725f48c46c87334da393dc79a9ab2d33e6c7fdd
parent7cc7984ab7c4c545333bbac44e130f478d5d825d (diff)
downloadnextcloud-server-2ea872d1562e77f486eb21323a2905b0585ea2f4.tar.gz
nextcloud-server-2ea872d1562e77f486eb21323a2905b0585ea2f4.zip
PoC: SystemTags endpoint to return tags used by a user with meta data
Target case is photos app: when visiting the tags category, all systemtags of the whole cloud are retrieved. In subequent steps the next tag is requested until the browser view is filled with tag tiles (i.e. previews are requested just as well). With this approach, we incorpoate the dav search and look for user related tags that are used by them, and already returns the statistics (number of files tagged with the respective tag) as well as a file id for the purpose to load the preview. This defaults to the file with the highest id. Call: curl -s -u 'user:password' \ 'https://my.nc.srv/remote.php/dav/systemtags-current' \ -X PROPFIND -H 'Accept: text/plain' \ -H 'Accept-Language: en-US,en;q=0.5' -H 'Depth: 1' \ -H 'Content-Type: text/plain;charset=UTF-8' \ --data @/home/doe/request-systemtag-props.xml With request-systemtag-props.xml: <?xml version="1.0" encoding="UTF-8"?> <d:propfind xmlns:d="DAV:"> <d:prop xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"> <oc:id/> <oc:display-name/> <oc:user-visible/> <oc:user-assignable/> <oc:can-assign/> <nc:files-assigned/> <nc:reference-fileid/> </d:prop> </d:propfind> Example output: … <d:response> <d:href>/master/remote.php/dav/systemtags/84</d:href> <d:propstat> <d:prop> <oc:id>84</oc:id> <oc:display-name>Computer</oc:display-name> <oc:user-visible>true</oc:user-visible> <oc:user-assignable>true</oc:user-assignable> <oc:can-assign>true</oc:can-assign> <nc:files-assigned>42</nc:files-assigned> <nc:reference-fileid>924022</nc:reference-fileid> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> <d:response> <d:href>/remote.php/dav/systemtags/97</d:href> <d:propstat> <d:prop> <oc:id>97</oc:id> <oc:display-name>Bear</oc:display-name> <oc:user-visible>true</oc:user-visible> <oc:user-assignable>true</oc:user-assignable> <oc:can-assign>true</oc:can-assign> <nc:files-assigned>1</nc:files-assigned> <nc:reference-fileid>923422</nc:reference-fileid> </d:prop> <d:status>HTTP/1.1 200 OK</d:status> </d:propstat> </d:response> … Signed-off-by: Arthur Schiwon <blizzz@arthur-schiwon.de>
-rw-r--r--apps/dav/composer/composer/autoload_classmap.php1
-rw-r--r--apps/dav/composer/composer/autoload_static.php1
-rw-r--r--apps/dav/lib/RootCollection.php7
-rw-r--r--apps/dav/lib/SystemTag/SystemTagNode.php19
-rw-r--r--apps/dav/lib/SystemTag/SystemTagPlugin.php24
-rw-r--r--apps/dav/lib/SystemTag/SystemTagsInUseCollection.php67
-rw-r--r--lib/private/Files/Cache/CacheQueryBuilder.php22
-rw-r--r--lib/private/Files/Cache/QuerySearchHelper.php58
-rw-r--r--lib/private/Files/Node/Folder.php64
9 files changed, 217 insertions, 46 deletions
diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php
index e7e2c34be62..6d0083e1de5 100644
--- a/apps/dav/composer/composer/autoload_classmap.php
+++ b/apps/dav/composer/composer/autoload_classmap.php
@@ -304,6 +304,7 @@ return array(
'OCA\\DAV\\SystemTag\\SystemTagNode' => $baseDir . '/../lib/SystemTag/SystemTagNode.php',
'OCA\\DAV\\SystemTag\\SystemTagPlugin' => $baseDir . '/../lib/SystemTag/SystemTagPlugin.php',
'OCA\\DAV\\SystemTag\\SystemTagsByIdCollection' => $baseDir . '/../lib/SystemTag/SystemTagsByIdCollection.php',
+ 'OCA\\DAV\\SystemTag\\SystemTagsInUseCollection' => $baseDir . '/../lib/SystemTag/SystemTagsInUseCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => $baseDir . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => $baseDir . '/../lib/SystemTag/SystemTagsRelationsCollection.php',
diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php
index 5fa87bc354a..aed08dd5520 100644
--- a/apps/dav/composer/composer/autoload_static.php
+++ b/apps/dav/composer/composer/autoload_static.php
@@ -319,6 +319,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\SystemTag\\SystemTagNode' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagNode.php',
'OCA\\DAV\\SystemTag\\SystemTagPlugin' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagPlugin.php',
'OCA\\DAV\\SystemTag\\SystemTagsByIdCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsByIdCollection.php',
+ 'OCA\\DAV\\SystemTag\\SystemTagsInUseCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsInUseCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectMappingCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectMappingCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsObjectTypeCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsObjectTypeCollection.php',
'OCA\\DAV\\SystemTag\\SystemTagsRelationsCollection' => __DIR__ . '/..' . '/../lib/SystemTag/SystemTagsRelationsCollection.php',
diff --git a/apps/dav/lib/RootCollection.php b/apps/dav/lib/RootCollection.php
index bacb550b415..ffc2c262cae 100644
--- a/apps/dav/lib/RootCollection.php
+++ b/apps/dav/lib/RootCollection.php
@@ -48,6 +48,7 @@ use OCP\Accounts\IAccountManager;
use OCP\App\IAppManager;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\IRootFolder;
use OCP\IConfig;
use Psr\Log\LoggerInterface;
use Sabre\DAV\SimpleCollection;
@@ -65,6 +66,7 @@ class RootCollection extends SimpleCollection {
$dispatcher = \OC::$server->get(IEventDispatcher::class);
$config = \OC::$server->get(IConfig::class);
$proxyMapper = \OC::$server->query(ProxyMapper::class);
+ $rootFolder = \OCP\Server::get(IRootFolder::class);
$userPrincipalBackend = new Principal(
$userManager,
@@ -131,6 +133,10 @@ class RootCollection extends SimpleCollection {
$groupManager,
\OC::$server->getEventDispatcher()
);
+ $systemTagInUseCollection = new SystemTag\SystemTagsInUseCollection(
+ $userSession,
+ $rootFolder
+ );
$commentsCollection = new Comments\RootCollection(
\OC::$server->getCommentsManager(),
$userManager,
@@ -179,6 +185,7 @@ class RootCollection extends SimpleCollection {
$systemAddressBookRoot]),
$systemTagCollection,
$systemTagRelationsCollection,
+ $systemTagInUseCollection,
$commentsCollection,
$uploadCollection,
$avatarCollection,
diff --git a/apps/dav/lib/SystemTag/SystemTagNode.php b/apps/dav/lib/SystemTag/SystemTagNode.php
index a31deb59a93..597aff84203 100644
--- a/apps/dav/lib/SystemTag/SystemTagNode.php
+++ b/apps/dav/lib/SystemTag/SystemTagNode.php
@@ -64,6 +64,9 @@ class SystemTagNode implements \Sabre\DAV\INode {
*/
protected $isAdmin;
+ protected int $numberOfFiles = -1;
+ protected int $referenceFileId = -1;
+
/**
* Sets up the node, expects a full path name
*
@@ -172,4 +175,20 @@ class SystemTagNode implements \Sabre\DAV\INode {
throw new NotFound('Tag with id ' . $this->tag->getId() . ' not found', 0, $e);
}
}
+
+ public function getNumberOfFiles(): int {
+ return $this->numberOfFiles;
+ }
+
+ public function setNumberOfFiles(int $numberOfFiles): void {
+ $this->numberOfFiles = $numberOfFiles;
+ }
+
+ public function getReferenceFileId(): int {
+ return $this->referenceFileId;
+ }
+
+ public function setReferenceFileId(int $referenceFileId): void {
+ $this->referenceFileId = $referenceFileId;
+ }
}
diff --git a/apps/dav/lib/SystemTag/SystemTagPlugin.php b/apps/dav/lib/SystemTag/SystemTagPlugin.php
index c21935edfdc..27007d7fb8b 100644
--- a/apps/dav/lib/SystemTag/SystemTagPlugin.php
+++ b/apps/dav/lib/SystemTag/SystemTagPlugin.php
@@ -56,6 +56,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
public const USERASSIGNABLE_PROPERTYNAME = '{http://owncloud.org/ns}user-assignable';
public const GROUPS_PROPERTYNAME = '{http://owncloud.org/ns}groups';
public const CANASSIGN_PROPERTYNAME = '{http://owncloud.org/ns}can-assign';
+ public const NUM_FILES_PROPERTYNAME = '{http://nextcloud.org/ns}files-assigned';
+ public const FILEID_PROPERTYNAME = '{http://nextcloud.org/ns}reference-fileid';
/**
* @var \Sabre\DAV\Server $server
@@ -224,6 +226,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
return;
}
+ // child nodes from systemtags-current should point to normal tag endpoint
+ if (preg_match('/^systemtags-current\/[0-9]+/', $propFind->getPath())) {
+ $propFind->setPath(str_replace('systemtags-current/', 'systemtags/', $propFind->getPath()));
+ }
+
$propFind->handle(self::ID_PROPERTYNAME, function () use ($node) {
return $node->getSystemTag()->getId();
});
@@ -258,6 +265,16 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
}
return implode('|', $groups);
});
+
+ if ($node instanceof SystemTagNode) {
+ $propFind->handle(self::NUM_FILES_PROPERTYNAME, function () use ($node): int {
+ return $node->getNumberOfFiles();
+ });
+
+ $propFind->handle(self::FILEID_PROPERTYNAME, function () use ($node): int {
+ return $node->getReferenceFileId();
+ });
+ }
}
/**
@@ -279,6 +296,8 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
self::USERVISIBLE_PROPERTYNAME,
self::USERASSIGNABLE_PROPERTYNAME,
self::GROUPS_PROPERTYNAME,
+ self::NUM_FILES_PROPERTYNAME,
+ self::FILEID_PROPERTYNAME,
], function ($props) use ($node) {
$tag = $node->getSystemTag();
$name = $tag->getName();
@@ -315,6 +334,11 @@ class SystemTagPlugin extends \Sabre\DAV\ServerPlugin {
$this->tagManager->setTagGroups($tag, $groupIds);
}
+ if (isset($props[self::NUM_FILES_PROPERTYNAME]) || isset($props[self::FILEID_PROPERTYNAME])) {
+ // read-only properties
+ throw new Forbidden();
+ }
+
if ($updateTag) {
$node->update($name, $userVisible, $userAssignable);
}
diff --git a/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php
new file mode 100644
index 00000000000..938b14e1f65
--- /dev/null
+++ b/apps/dav/lib/SystemTag/SystemTagsInUseCollection.php
@@ -0,0 +1,67 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @author Arthur Schiwon <blizzz@arthur-schiwon.de>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\DAV\SystemTag;
+
+use OC\SystemTag\SystemTag;
+use OCP\Files\IRootFolder;
+use OCP\IUserSession;
+use OCP\SystemTag\ISystemTagManager;
+use Sabre\DAV\Exception\Forbidden;
+
+class SystemTagsInUseCollection extends \Sabre\DAV\SimpleCollection {
+ protected IUserSession $userSession;
+ protected IRootFolder $rootFolder;
+
+ public function __construct(IUserSession $userSession, IRootFolder $rootFolder) {
+ $this->userSession = $userSession;
+ $this->rootFolder = $rootFolder;
+ $this->name = 'systemtags-current';
+ }
+
+ public function setName($name): void {
+ throw new Forbidden('Permission denied to rename this collection');
+ }
+
+ public function getChildren() {
+ $user = $this->userSession->getUser();
+ if ($user === null) {
+ throw new Forbidden('Permission denied to read this collection');
+ }
+
+ $userFolder = $this->rootFolder->getUserFolder($user->getUID());
+ $result = $userFolder->getSystemTags('image');
+ $children = [];
+ foreach ($result as $tagData) {
+ $tag = new SystemTag((string)$tagData['id'], $tagData['name'], (bool)$tagData['visibility'], (bool)$tagData['editable']);
+ $node = new SystemTagNode($tag, $user, false, \OCP\Server::get(ISystemTagManager::class));
+ $node->setNumberOfFiles($tagData['number_files']);
+ $node->setReferenceFileId($tagData['ref_file_id']);
+ $children[] = $node;
+ }
+ return $children;
+ }
+}
diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php
index 496a8361d77..c5563750c4d 100644
--- a/lib/private/Files/Cache/CacheQueryBuilder.php
+++ b/lib/private/Files/Cache/CacheQueryBuilder.php
@@ -41,8 +41,28 @@ class CacheQueryBuilder extends QueryBuilder {
parent::__construct($connection, $systemConfig, $logger);
}
+ public function selectTagUsage(): self {
+ $this
+ ->select('systemtag.name', 'systemtag.id', 'systemtag.visibility', 'systemtag.editable')
+ ->selectAlias($this->createFunction('COUNT(filecache.fileid)'), 'number_files')
+ ->selectAlias($this->createFunction('MAX(filecache.fileid)'), 'ref_file_id')
+ ->from('filecache', 'filecache')
+ ->leftJoin('filecache', 'systemtag_object_mapping', 'systemtagmap', $this->expr()->andX(
+ $this->expr()->eq('filecache.fileid', $this->expr()->castColumn('systemtagmap.objectid', IQueryBuilder::PARAM_INT)),
+ $this->expr()->eq('systemtagmap.objecttype', $this->createNamedParameter('files'))
+ ))
+ ->leftJoin('systemtagmap', 'systemtag', 'systemtag', $this->expr()->andX(
+ $this->expr()->eq('systemtag.id', 'systemtagmap.systemtagid'),
+ $this->expr()->eq('systemtag.visibility', $this->createNamedParameter(true))
+ ))
+ ->where($this->expr()->like('systemtag.name', $this->createNamedParameter('_%')))
+ ->groupBy('systemtag.name', 'systemtag.id', 'systemtag.visibility', 'systemtag.editable');
+
+ return $this;
+ }
+
public function selectFileCache(string $alias = null, bool $joinExtendedCache = true) {
- $name = $alias ? $alias : 'filecache';
+ $name = $alias ?: 'filecache';
$this->select("$name.fileid", 'storage', 'path', 'path_hash', "$name.parent", "$name.name", 'mimetype', 'mimepart', 'size', 'mtime',
'storage_mtime', 'encrypted', 'etag', 'permissions', 'checksum', 'unencrypted_size')
->from('filecache', $name);
diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php
index eba2aac927b..c2eed5688b5 100644
--- a/lib/private/Files/Cache/QuerySearchHelper.php
+++ b/lib/private/Files/Cache/QuerySearchHelper.php
@@ -74,6 +74,41 @@ class QuerySearchHelper {
);
}
+ protected function applySearchConstraints(CacheQueryBuilder $query, ISearchQuery $searchQuery, array $caches): void {
+ $storageFilters = array_values(array_map(function (ICache $cache) {
+ return $cache->getQueryFilterForStorage();
+ }, $caches));
+ $storageFilter = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $storageFilters);
+ $filter = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [$searchQuery->getSearchOperation(), $storageFilter]);
+ $this->queryOptimizer->processOperator($filter);
+
+ $searchExpr = $this->searchBuilder->searchOperatorToDBExpr($query, $filter);
+ if ($searchExpr) {
+ $query->andWhere($searchExpr);
+ }
+
+ $this->searchBuilder->addSearchOrdersToQuery($query, $searchQuery->getOrder());
+
+ if ($searchQuery->getLimit()) {
+ $query->setMaxResults($searchQuery->getLimit());
+ }
+ if ($searchQuery->getOffset()) {
+ $query->setFirstResult($searchQuery->getOffset());
+ }
+ }
+
+ public function findUsedTagsInCaches(ISearchQuery $searchQuery, array $caches): array {
+ $query = $this->getQueryBuilder();
+ $query->selectTagUsage();
+
+ $this->applySearchConstraints($query, $searchQuery, $caches);
+
+ $result = $query->execute();
+ $tags = $result->fetchAll();
+ $result->closeCursor();
+ return $tags;
+ }
+
/**
* Perform a file system search in multiple caches
*
@@ -127,26 +162,7 @@ class QuerySearchHelper {
));
}
- $storageFilters = array_values(array_map(function (ICache $cache) {
- return $cache->getQueryFilterForStorage();
- }, $caches));
- $storageFilter = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_OR, $storageFilters);
- $filter = new SearchBinaryOperator(ISearchBinaryOperator::OPERATOR_AND, [$searchQuery->getSearchOperation(), $storageFilter]);
- $this->queryOptimizer->processOperator($filter);
-
- $searchExpr = $this->searchBuilder->searchOperatorToDBExpr($builder, $filter);
- if ($searchExpr) {
- $query->andWhere($searchExpr);
- }
-
- $this->searchBuilder->addSearchOrdersToQuery($query, $searchQuery->getOrder());
-
- if ($searchQuery->getLimit()) {
- $query->setMaxResults($searchQuery->getLimit());
- }
- if ($searchQuery->getOffset()) {
- $query->setFirstResult($searchQuery->getOffset());
- }
+ $this->applySearchConstraints($query, $searchQuery, $caches);
$result = $query->execute();
$files = $result->fetchAll();
@@ -158,7 +174,7 @@ class QuerySearchHelper {
$result->closeCursor();
// loop through all caches for each result to see if the result matches that storage
- // results are grouped by the same array keys as the caches argument to allow the caller to distringuish the source of the results
+ // results are grouped by the same array keys as the caches argument to allow the caller to distinguish the source of the results
$results = array_fill_keys(array_keys($caches), []);
foreach ($rawEntries as $rawEntry) {
foreach ($caches as $cacheKey => $cache) {
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 90aed642a2d..a34e1315385 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -203,7 +203,7 @@ class Folder extends Node implements \OCP\Files\Folder {
throw new NotPermittedException('No create permission for path');
}
- private function queryFromOperator(ISearchOperator $operator, string $uid = null): ISearchQuery {
+ private function queryFromOperator(ISearchOperator $operator, string $uid = null, int $limit = 0, int $offset = 0): ISearchQuery {
if ($uid === null) {
$user = null;
} else {
@@ -211,36 +211,17 @@ class Folder extends Node implements \OCP\Files\Folder {
$userManager = \OC::$server->query(IUserManager::class);
$user = $userManager->get($uid);
}
- return new SearchQuery($operator, 0, 0, [], $user);
+ return new SearchQuery($operator, $limit, $offset, [], $user);
}
/**
- * search for files with the name matching $query
- *
- * @param string|ISearchQuery $query
- * @return \OC\Files\Node\Node[]
+ * @psalm-return list{0: array<string, \OCP\Files\Cache\ICache>, 1: array<string, \OCP\Files\Mount\IMountPoint>}
*/
- public function search($query) {
- if (is_string($query)) {
- $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
- }
-
- // search is handled by a single query covering all caches that this folder contains
- // this is done by collect
-
- $limitToHome = $query->limitToHome();
- if ($limitToHome && count(explode('/', $this->path)) !== 3) {
- throw new \InvalidArgumentException('searching by owner is only allows on the users home folder');
- }
-
+ protected function getCachesAndMountpointsForSearch(bool $limitToHome = false): array {
$rootLength = strlen($this->path);
$mount = $this->root->getMount($this->path);
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($this->path);
-
- // collect all caches for this folder, indexed by their mountpoint relative to this folder
- // and save the mount which is needed later to construct the FileInfo objects
-
if ($internalPath !== '') {
// a temporary CacheJail is used to handle filtering down the results to within this folder
$caches = ['' => new CacheJail($storage->getCache(''), $internalPath)];
@@ -261,12 +242,36 @@ class Folder extends Node implements \OCP\Files\Folder {
}
}
+ return [$caches, $mountByMountPoint];
+ }
+
+ /**
+ * search for files with the name matching $query
+ *
+ * @param string|ISearchQuery $query
+ * @return \OC\Files\Node\Node[]
+ */
+ public function search($query) {
+ if (is_string($query)) {
+ $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'name', '%' . $query . '%'));
+ }
+
+ // search is handled by a single query covering all caches that this folder contains
+ // this is done by collect
+
+ $limitToHome = $query->limitToHome();
+ if ($limitToHome && count(explode('/', $this->path)) !== 3) {
+ throw new \InvalidArgumentException('searching by owner is only allows on the users home folder');
+ }
+
+ [$caches, $mountByMountPoint] = $this->getCachesAndMountpointsForSearch($limitToHome);
+
/** @var QuerySearchHelper $searchHelper */
$searchHelper = \OC::$server->get(QuerySearchHelper::class);
$resultsPerCache = $searchHelper->searchInCaches($query, $caches);
// loop through all results per-cache, constructing the FileInfo object from the CacheEntry and merge them all
- $files = array_merge(...array_map(function (array $results, $relativeMountPoint) use ($mountByMountPoint) {
+ $files = array_merge(...array_map(function (array $results, string $relativeMountPoint) use ($mountByMountPoint) {
$mount = $mountByMountPoint[$relativeMountPoint];
return array_map(function (ICacheEntry $result) use ($relativeMountPoint, $mount) {
return $this->cacheEntryToFileInfo($mount, $relativeMountPoint, $result);
@@ -332,6 +337,17 @@ class Folder extends Node implements \OCP\Files\Folder {
}
/**
+ * @return Node[]
+ */
+ public function getSystemTags(string $mediaType, int $limit = 0, int $offset = 0): array {
+ $query = $this->queryFromOperator(new SearchComparison(ISearchComparison::COMPARE_LIKE, 'mimetype', $mediaType . '/%'), null, $limit, $offset);
+ [$caches, ] = $this->getCachesAndMountpointsForSearch();
+ /** @var QuerySearchHelper $searchHelper */
+ $searchHelper = \OCP\Server::get(QuerySearchHelper::class);
+ return $searchHelper->findUsedTagsInCaches($query, $caches);
+ }
+
+ /**
* @param int $id
* @return \OC\Files\Node\Node[]
*/