aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/lib/Connector/Sabre/FilesPlugin.php9
-rw-r--r--apps/dav/lib/Files/FileSearchBackend.php102
-rw-r--r--apps/dav/lib/Server.php5
-rw-r--r--apps/dav/tests/unit/Files/FileSearchBackendTest.php5
-rw-r--r--apps/files/lib/Command/Scan.php15
-rw-r--r--apps/files_trashbin/lib/Trash/TrashItem.php10
6 files changed, 98 insertions, 48 deletions
diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php
index 709a4cd68ed..9319327d094 100644
--- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php
+++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php
@@ -7,6 +7,7 @@
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
* @author Joas Schilling <coding@schilljs.com>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Michael Jobst <mjobst+github@tecratech.de>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
@@ -49,8 +50,8 @@ use Sabre\DAV\IFile;
use Sabre\DAV\INode;
use Sabre\DAV\PropFind;
use Sabre\DAV\PropPatch;
-use Sabre\DAV\ServerPlugin;
use Sabre\DAV\Server;
+use Sabre\DAV\ServerPlugin;
use Sabre\DAV\Tree;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
@@ -84,6 +85,7 @@ class FilesPlugin extends ServerPlugin {
public const SHARE_NOTE = '{http://nextcloud.org/ns}note';
public const SUBFOLDER_COUNT_PROPERTYNAME = '{http://nextcloud.org/ns}contained-folder-count';
public const SUBFILE_COUNT_PROPERTYNAME = '{http://nextcloud.org/ns}contained-file-count';
+ public const FILE_METADATA_PREFIX = '{http://nextcloud.org/ns}metadata-';
public const FILE_METADATA_SIZE = '{http://nextcloud.org/ns}file-metadata-size';
public const FILE_METADATA_GPS = '{http://nextcloud.org/ns}file-metadata-gps';
@@ -389,6 +391,11 @@ class FilesPlugin extends ServerPlugin {
$propFind->handle(self::CREATION_TIME_PROPERTYNAME, function () use ($node) {
return $node->getFileInfo()->getCreationTime();
});
+
+ foreach ($node->getFileInfo()->getMetadata() as $metadataKey => $metadataValue) {
+ $propFind->handle(self::FILE_METADATA_PREFIX . $metadataKey, $metadataValue);
+ }
+
/**
* Return file/folder name as displayname. The primary reason to
* implement it this way is to avoid costly fallback to
diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php
index 524f90e6623..658ad34ec32 100644
--- a/apps/dav/lib/Files/FileSearchBackend.php
+++ b/apps/dav/lib/Files/FileSearchBackend.php
@@ -4,6 +4,7 @@
*
* @author Christian <16852529+cviereck@users.noreply.github.com>
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
*
@@ -42,6 +43,9 @@ use OCP\Files\Node;
use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchOrder;
use OCP\Files\Search\ISearchQuery;
+use OCP\FilesMetadata\IFilesMetadataManager;
+use OCP\FilesMetadata\Model\IMetadataQuery;
+use OCP\FilesMetadata\Model\IMetadataValueWrapper;
use OCP\IUser;
use OCP\Share\IManager;
use Sabre\DAV\Exception\NotFound;
@@ -57,37 +61,14 @@ use SearchDAV\Query\Query;
class FileSearchBackend implements ISearchBackend {
public const OPERATOR_LIMIT = 100;
- /** @var CachingTree */
- private $tree;
-
- /** @var IUser */
- private $user;
-
- /** @var IRootFolder */
- private $rootFolder;
-
- /** @var IManager */
- private $shareManager;
-
- /** @var View */
- private $view;
-
- /**
- * FileSearchBackend constructor.
- *
- * @param CachingTree $tree
- * @param IUser $user
- * @param IRootFolder $rootFolder
- * @param IManager $shareManager
- * @param View $view
- * @internal param IRootFolder $rootFolder
- */
- public function __construct(CachingTree $tree, IUser $user, IRootFolder $rootFolder, IManager $shareManager, View $view) {
- $this->tree = $tree;
- $this->user = $user;
- $this->rootFolder = $rootFolder;
- $this->shareManager = $shareManager;
- $this->view = $view;
+ public function __construct(
+ private CachingTree $tree,
+ private IUser $user,
+ private IRootFolder $rootFolder,
+ private IManager $shareManager,
+ private View $view,
+ private IFilesMetadataManager $filesMetadataManager,
+ ) {
}
/**
@@ -115,7 +96,7 @@ class FileSearchBackend implements ISearchBackend {
// all valid scopes support the same schema
//todo dynamically load all propfind properties that are supported
- return [
+ $props = [
// queryable properties
new SearchPropertyDefinition('{DAV:}displayname', true, true, true),
new SearchPropertyDefinition('{DAV:}getcontenttype', true, true, true),
@@ -137,6 +118,33 @@ class FileSearchBackend implements ISearchBackend {
new SearchPropertyDefinition(FilesPlugin::FILE_METADATA_SIZE, true, false, false, SearchPropertyDefinition::DATATYPE_STRING),
new SearchPropertyDefinition(FilesPlugin::FILEID_PROPERTYNAME, true, false, false, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER),
];
+
+ return array_merge($props, $this->getPropertyDefinitionsForMetadata());
+ }
+
+
+ private function getPropertyDefinitionsForMetadata(): array {
+ $metadataProps = [];
+ $metadata = $this->filesMetadataManager->getKnownMetadata();
+ $indexes = $metadata->getIndexes();
+ foreach ($metadata->getKeys() as $key) {
+ $isIndex = in_array($key, $indexes);
+ $type = match ($metadata->getType($key)) {
+ IMetadataValueWrapper::TYPE_INT => SearchPropertyDefinition::DATATYPE_INTEGER,
+ IMetadataValueWrapper::TYPE_FLOAT => SearchPropertyDefinition::DATATYPE_DECIMAL,
+ IMetadataValueWrapper::TYPE_BOOL => SearchPropertyDefinition::DATATYPE_BOOLEAN,
+ default => SearchPropertyDefinition::DATATYPE_STRING
+ };
+ $metadataProps[] = new SearchPropertyDefinition(
+ FilesPlugin::FILE_METADATA_PREFIX . $key,
+ true,
+ $isIndex,
+ $isIndex,
+ $type
+ );
+ }
+
+ return $metadataProps;
}
/**
@@ -300,11 +308,20 @@ class FileSearchBackend implements ISearchBackend {
/**
* @param Query $query
+ *
* @return ISearchQuery
*/
private function transformQuery(Query $query): ISearchQuery {
+ $orders = array_map(function (Order $order): ISearchOrder {
+ $direction = $order->order === Order::ASC ? ISearchOrder::DIRECTION_ASCENDING : ISearchOrder::DIRECTION_DESCENDING;
+ if (str_starts_with($order->property->name, FilesPlugin::FILE_METADATA_PREFIX)) {
+ return new SearchOrder($direction, substr($order->property->name, strlen(FilesPlugin::FILE_METADATA_PREFIX)), IMetadataQuery::EXTRA);
+ } else {
+ return new SearchOrder($direction, $this->mapPropertyNameToColumn($order->property));
+ }
+ }, $query->orderBy);
+
$limit = $query->limit;
- $orders = array_map([$this, 'mapSearchOrder'], $query->orderBy);
$offset = $limit->firstResult;
$limitHome = false;
@@ -353,14 +370,6 @@ class FileSearchBackend implements ISearchBackend {
}
/**
- * @param Order $order
- * @return ISearchOrder
- */
- private function mapSearchOrder(Order $order) {
- return new SearchOrder($order->order === Order::ASC ? ISearchOrder::DIRECTION_ASCENDING : ISearchOrder::DIRECTION_DESCENDING, $this->mapPropertyNameToColumn($order->property));
- }
-
- /**
* @param Operator $operator
* @return ISearchOperator
*/
@@ -387,7 +396,16 @@ class FileSearchBackend implements ISearchBackend {
if (!($operator->arguments[1] instanceof Literal)) {
throw new \InvalidArgumentException('Invalid argument 2 for ' . $trimmedType . ' operation, expected literal');
}
- return new SearchComparison($trimmedType, $this->mapPropertyNameToColumn($operator->arguments[0]), $this->castValue($operator->arguments[0], $operator->arguments[1]->value));
+
+ $property = $operator->arguments[0];
+ $value = $this->castValue($property, $operator->arguments[1]->value);
+ if (str_starts_with($property->name, FilesPlugin::FILE_METADATA_PREFIX)) {
+ return new SearchComparison($trimmedType, substr($property->name, strlen(FilesPlugin::FILE_METADATA_PREFIX)), $value, IMetadataQuery::EXTRA);
+ } else {
+ return new SearchComparison($trimmedType, $this->mapPropertyNameToColumn($property), $value);
+ }
+
+ // no break
case Operator::OPERATION_IS_COLLECTION:
return new SearchComparison('eq', 'mimetype', ICacheEntry::DIRECTORY_MIMETYPE);
default:
diff --git a/apps/dav/lib/Server.php b/apps/dav/lib/Server.php
index 603e015fca9..15b97d028cc 100644
--- a/apps/dav/lib/Server.php
+++ b/apps/dav/lib/Server.php
@@ -11,6 +11,7 @@
* @author Joas Schilling <coding@schilljs.com>
* @author John Molakvoæ <skjnldsv@protonmail.com>
* @author Lukas Reschke <lukas@statuscode.ch>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Morris Jobke <hey@morrisjobke.de>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -76,6 +77,7 @@ use OCA\DAV\Upload\ChunkingV2Plugin;
use OCP\AppFramework\Http\Response;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\ICacheFactory;
use OCP\IRequest;
use OCP\Profiler\IProfiler;
@@ -316,7 +318,8 @@ class Server {
$user,
\OC::$server->getRootFolder(),
\OC::$server->getShareManager(),
- $view
+ $view,
+ \OCP\Server::get(IFilesMetadataManager::class)
));
$this->server->addPlugin(
new BulkUploadPlugin(
diff --git a/apps/dav/tests/unit/Files/FileSearchBackendTest.php b/apps/dav/tests/unit/Files/FileSearchBackendTest.php
index 715130d2fae..ea841140201 100644
--- a/apps/dav/tests/unit/Files/FileSearchBackendTest.php
+++ b/apps/dav/tests/unit/Files/FileSearchBackendTest.php
@@ -41,6 +41,7 @@ use OCP\Files\IRootFolder;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchComparison;
use OCP\Files\Search\ISearchQuery;
+use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\IUser;
use OCP\Share\IManager;
use SearchDAV\Backend\SearchPropertyDefinition;
@@ -114,7 +115,9 @@ class FileSearchBackendTest extends TestCase {
->method('get')
->willReturn($this->searchFolder);
- $this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view);
+ $filesMetadataManager = $this->createMock(IFilesMetadataManager::class);
+
+ $this->search = new FileSearchBackend($this->tree, $this->user, $this->rootFolder, $this->shareManager, $this->view, $filesMetadataManager);
}
public function testSearchFilename(): void {
diff --git a/apps/files/lib/Command/Scan.php b/apps/files/lib/Command/Scan.php
index f5ac3627196..b1fc25bfe9b 100644
--- a/apps/files/lib/Command/Scan.php
+++ b/apps/files/lib/Command/Scan.php
@@ -11,6 +11,7 @@
* @author Joel S <joel.devbox@protonmail.com>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
* @author martin.mattel@diemattels.at <martin.mattel@diemattels.at>
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Robin Appelman <robin@icewind.nl>
* @author Roeland Jago Douma <roeland@famdouma.nl>
* @author Thomas Müller <thomas.mueller@tmit.eu>
@@ -37,17 +38,19 @@ use OC\Core\Command\Base;
use OC\Core\Command\InterruptedException;
use OC\DB\Connection;
use OC\DB\ConnectionAdapter;
+use OC\FilesMetadata\FilesMetadataManager;
+use OC\ForbiddenException;
+use OC\Metadata\MetadataManager;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Events\FileCacheUpdated;
use OCP\Files\Events\NodeAddedToCache;
use OCP\Files\Events\NodeRemovedFromCache;
use OCP\Files\File;
-use OC\ForbiddenException;
-use OC\Metadata\MetadataManager;
-use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\IRootFolder;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\Files\StorageNotAvailableException;
+use OCP\FilesMetadata\IFilesMetadataManager;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Helper\Table;
@@ -69,6 +72,7 @@ class Scan extends Base {
private IUserManager $userManager,
private IRootFolder $rootFolder,
private MetadataManager $metadataManager,
+ private FilesMetadataManager $filesMetadataManager,
private IEventDispatcher $eventDispatcher,
private LoggerInterface $logger,
) {
@@ -140,6 +144,11 @@ class Scan extends Base {
if ($node instanceof File) {
$this->metadataManager->generateMetadata($node, false);
}
+
+ $this->filesMetadataManager->refreshMetadata(
+ $node,
+ IFilesMetadataManager::PROCESS_LIVE | IFilesMetadataManager::PROCESS_BACKGROUND
+ );
}
});
diff --git a/apps/files_trashbin/lib/Trash/TrashItem.php b/apps/files_trashbin/lib/Trash/TrashItem.php
index 3bfc905d3a1..99b2d3a1a2c 100644
--- a/apps/files_trashbin/lib/Trash/TrashItem.php
+++ b/apps/files_trashbin/lib/Trash/TrashItem.php
@@ -2,6 +2,7 @@
/**
* @copyright Copyright (c) 2018 Robin Appelman <robin@icewind.nl>
*
+ * @author Maxence Lange <maxence@artificial-owl.com>
* @author Robin Appelman <robin@icewind.nl>
*
* @license GNU AGPL version 3 or any later version
@@ -23,6 +24,7 @@
namespace OCA\Files_Trashbin\Trash;
use OCP\Files\FileInfo;
+use OCP\FilesMetadata\Model\IFilesMetadata;
use OCP\IUser;
class TrashItem implements ITrashItem {
@@ -190,4 +192,12 @@ class TrashItem implements ITrashItem {
public function getParentId(): int {
return $this->fileInfo->getParentId();
}
+
+ /**
+ * @inheritDoc
+ * @return array<string, int|string|bool|float|string[]|int[]>
+ */
+ public function getMetadata(): array {
+ return $this->fileInfo->getMetadata();
+ }
}