Skip to content

Commit

Permalink
IFilesMetadata
Browse files Browse the repository at this point in the history
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
  • Loading branch information
ArtificialOwl committed Nov 7, 2023
1 parent d439317 commit e62e9e3
Show file tree
Hide file tree
Showing 44 changed files with 3,721 additions and 144 deletions.
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

0 comments on commit e62e9e3

Please sign in to comment.