Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IFilesMetadata #40761

Merged
merged 3 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion apps/dav/lib/Connector/Sabre/FilesPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -49,8 +50,8 @@
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;
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -389,6 +391,11 @@ public function handleGetProperties(PropFind $propFind, \Sabre\DAV\INode $node)
$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
Expand Down
102 changes: 60 additions & 42 deletions apps/dav/lib/Files/FileSearchBackend.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
*
Expand Down Expand Up @@ -42,6 +43,9 @@
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;
Expand All @@ -57,37 +61,14 @@
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,
) {
}

/**
Expand Down Expand Up @@ -115,7 +96,7 @@ public function getPropertyDefinitionsForScope(string $href, ?string $path): arr
// 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),
Expand All @@ -137,6 +118,33 @@ public function getPropertyDefinitionsForScope(string $href, ?string $path): arr
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;
}

/**
Expand Down Expand Up @@ -300,11 +308,20 @@ private function getHrefForNode(Node $node) {

/**
* @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;
Expand Down Expand Up @@ -352,14 +369,6 @@ private function countSearchOperators(Operator $operator): int {
}
}

/**
* @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
Expand Down Expand Up @@ -387,7 +396,16 @@ private function transformSearchOperation(Operator $operator) {
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:
Expand Down
5 changes: 4 additions & 1 deletion apps/dav/lib/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -76,6 +77,7 @@
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;
Expand Down Expand Up @@ -316,7 +318,8 @@ public function __construct(IRequest $request, string $baseUri) {
$user,
\OC::$server->getRootFolder(),
\OC::$server->getShareManager(),
$view
$view,
\OCP\Server::get(IFilesMetadataManager::class)
));
$this->server->addPlugin(
new BulkUploadPlugin(
Expand Down
15 changes: 12 additions & 3 deletions apps/files/lib/Command/Scan.php
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -37,17 +38,19 @@
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;
Expand All @@ -69,6 +72,7 @@ public function __construct(
private IUserManager $userManager,
private IRootFolder $rootFolder,
private MetadataManager $metadataManager,
private FilesMetadataManager $filesMetadataManager,
private IEventDispatcher $eventDispatcher,
private LoggerInterface $logger,
) {
Expand Down Expand Up @@ -140,6 +144,11 @@ protected function scanFiles(string $user, string $path, bool $scanMetadata, Out
if ($node instanceof File) {
$this->metadataManager->generateMetadata($node, false);
}

$this->filesMetadataManager->refreshMetadata(
$node,
IFilesMetadataManager::PROCESS_LIVE | IFilesMetadataManager::PROCESS_BACKGROUND
);
}
});

Expand Down
10 changes: 10 additions & 0 deletions apps/files_trashbin/lib/Trash/TrashItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -190,4 +192,12 @@ public function getUploadTime(): int {
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();
}
}
Loading
Loading