diff --git a/apps/dav/tests/unit/Files/FileSearchBackendTest.php b/apps/dav/tests/unit/Files/FileSearchBackendTest.php index 715130d2faeef..ea84114020194 100644 --- a/apps/dav/tests/unit/Files/FileSearchBackendTest.php +++ b/apps/dav/tests/unit/Files/FileSearchBackendTest.php @@ -41,6 +41,7 @@ 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 @@ protected function setUp(): void { ->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/core/Command/FilesMetadata/Get.php b/core/Command/FilesMetadata/Get.php index aebabe63e359f..99bc167f71d1e 100644 --- a/core/Command/FilesMetadata/Get.php +++ b/core/Command/FilesMetadata/Get.php @@ -91,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($input->getOption('reset')) { $this->filesMetadataManager->deleteMetadata($fileId); if (!$input->getOption('refresh')) { - return 0; + return self::SUCCESS; } } @@ -114,6 +114,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output->writeln(json_encode($metadata, JSON_PRETTY_PRINT)); } - return 0; + return self::SUCCESS; } } diff --git a/lib/private/Files/Cache/SearchBuilder.php b/lib/private/Files/Cache/SearchBuilder.php index ba4aabf2b4fb7..1f9a6af931b2d 100644 --- a/lib/private/Files/Cache/SearchBuilder.php +++ b/lib/private/Files/Cache/SearchBuilder.php @@ -78,7 +78,7 @@ public function extractRequestedFields(ISearchOperator $operator): array { return array_reduce($operator->getArguments(), function (array $fields, ISearchOperator $operator) { return array_unique(array_merge($fields, $this->extractRequestedFields($operator))); }, []); - } elseif ($operator instanceof ISearchComparison && !$operator->isExtra()) { + } elseif ($operator instanceof ISearchComparison && !$operator->getExtra()) { return [$operator->getField()]; } return []; diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php index eba7ce1d77e00..c7462572fed06 100644 --- a/lib/private/Files/Node/Folder.php +++ b/lib/private/Files/Node/Folder.php @@ -252,8 +252,6 @@ public function search($query) { if ($order) { usort($files, function (FileInfo $a, FileInfo $b) use ($order) { foreach ($order as $orderField) { - // needed !? - // if ($orderField->isExtra()) { continue; } $cmp = $orderField->sortFileInfo($a, $b); if ($cmp !== 0) { return $cmp; diff --git a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php index cf9e6ad5b91bc..664402f1238c8 100644 --- a/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php +++ b/lib/private/Files/Search/QueryOptimizer/PathPrefixOptimizer.php @@ -51,7 +51,7 @@ public function inspectOperator(ISearchOperator $operator): void { } public function processOperator(ISearchOperator &$operator) { - if (!$this->useHashEq && $operator instanceof ISearchComparison && !$operator->isExtra() && $operator->getField() === 'path' && $operator->getType() === ISearchComparison::COMPARE_EQUAL) { + if (!$this->useHashEq && $operator instanceof ISearchComparison && !$operator->getExtra() && $operator->getField() === 'path' && $operator->getType() === ISearchComparison::COMPARE_EQUAL) { $operator->setQueryHint(ISearchComparison::HINT_PATH_EQ_HASH, false); } @@ -72,7 +72,7 @@ private function isPathPrefixOperator(ISearchOperator $operator): bool { private function operatorPairIsPathPrefix(ISearchOperator $like, ISearchOperator $equal): bool { return ( $like instanceof ISearchComparison && $equal instanceof ISearchComparison && - !$like->isExtra() && !$equal->isExtra() && $like->getField() === 'path' && $equal->getField() === 'path' && + !$like->getExtra() && !$equal->getExtra() && $like->getField() === 'path' && $equal->getField() === 'path' && $like->getType() === ISearchComparison::COMPARE_LIKE_CASE_SENSITIVE && $equal->getType() === ISearchComparison::COMPARE_EQUAL && $like->getValue() === SearchComparison::escapeLikeParameter($equal->getValue()) . '/%' ); diff --git a/lib/private/Files/Search/SearchComparison.php b/lib/private/Files/Search/SearchComparison.php index 5caa632f6184c..4f9ac266397bd 100644 --- a/lib/private/Files/Search/SearchComparison.php +++ b/lib/private/Files/Search/SearchComparison.php @@ -1,4 +1,6 @@ * @@ -39,32 +41,32 @@ public function __construct( /** * @return string */ - public function getType() { + public function getType(): string { return $this->type; } /** * @return string */ - public function getField() { + public function getField(): string { return $this->field; } /** * @return \DateTime|int|string */ - public function getValue() { + public function getValue(): string|int|\DateTime { return $this->value; } + /** + * @return string + * @since 28.0.0 + */ public function getExtra(): string { return $this->extra; } - public function isExtra(): bool { - return ($this->extra !== ''); - } - public function getQueryHint(string $name, $default) { return $this->hints[$name] ?? $default; } diff --git a/lib/private/Files/Search/SearchOrder.php b/lib/private/Files/Search/SearchOrder.php index ca974ca9c034c..de514262bf5e0 100644 --- a/lib/private/Files/Search/SearchOrder.php +++ b/lib/private/Files/Search/SearchOrder.php @@ -48,14 +48,14 @@ public function getField(): string { return $this->field; } + /** + * @return string + * @since 28.0.0 + */ public function getExtra(): string { return $this->extra; } - public function isExtra(): bool { - return ($this->extra !== ''); - } - public function sortFileInfo(FileInfo $a, FileInfo $b): int { $cmp = $this->sortFileInfoNoDirection($a, $b); return $cmp * ($this->direction === ISearchOrder::DIRECTION_ASCENDING ? 1 : -1); diff --git a/lib/private/FilesMetadata/FilesMetadataManager.php b/lib/private/FilesMetadata/FilesMetadataManager.php index 7e941234ce3f4..54310f934d72a 100644 --- a/lib/private/FilesMetadata/FilesMetadataManager.php +++ b/lib/private/FilesMetadata/FilesMetadataManager.php @@ -242,6 +242,7 @@ public function getKnownMetadata(): IFilesMetadata { /** * @param string $key metadata key * @param string $type metadata type + * @param bool $indexed TRUE if metadata can be search * * @inheritDoc * @since 28.0.0 @@ -253,17 +254,17 @@ public function getKnownMetadata(): IFilesMetadata { * @see IMetadataValueWrapper::TYPE_INT_LIST * @see IMetadataValueWrapper::TYPE_STRING */ - public function initMetadataIndex(string $key, string $type): void { + public function initMetadata(string $key, string $type, bool $indexed): void { $current = $this->getKnownMetadata(); try { - if ($current->getType($key) === $type && $current->isIndex($key)) { - return; // if key exists, with same type and is already indexed, we do nothing. + if ($current->getType($key) === $type && $indexed === $current->isIndex($key)) { + return; // if key exists, with same type and indexed, we do nothing. } } catch (FilesMetadataNotFoundException) { // if value does not exist, we keep on the writing of course } - $current->import([$key => ['type' => $type, 'indexed' => true]]); + $current->import([$key => ['type' => $type, 'indexed' => $indexed]]); $this->config->setAppValue('core', self::CONFIG_KEY, json_encode($current)); } diff --git a/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php index d628e468cdd2a..ff7dfcb8368cb 100644 --- a/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php +++ b/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php @@ -33,6 +33,7 @@ use OCP\Files\NotPermittedException; use OCP\FilesMetadata\Event\MetadataLiveEvent; use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; /** * Simple background job, created when requested by an app during the @@ -47,6 +48,7 @@ public function __construct( ITimeFactory $time, private IRootFolder $rootFolder, private FilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger ) { parent::__construct($time); } @@ -60,7 +62,8 @@ protected function run($argument) { $file = array_shift($node); $this->filesMetadataManager->refreshMetadata($file, IFilesMetadataManager::PROCESS_BACKGROUND); } - } catch (NotPermittedException|NoUserException $e) { + } catch (\Exception $e) { + $this->logger->warning('issue while running UpdateSingleMetadata', ['exception' => $e, 'userId' => $userId, 'fileId' => $fileId]); } } } diff --git a/lib/private/FilesMetadata/Listener/MetadataDelete.php b/lib/private/FilesMetadata/Listener/MetadataDelete.php index 7f8fd03573503..25c944475a9ee 100644 --- a/lib/private/FilesMetadata/Listener/MetadataDelete.php +++ b/lib/private/FilesMetadata/Listener/MetadataDelete.php @@ -30,6 +30,7 @@ use OCP\EventDispatcher\IEventListener; use OCP\Files\Events\Node\NodeDeletedEvent; use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; /** * Handle file deletion event and remove stored metadata related to the deleted file @@ -39,6 +40,7 @@ class MetadataDelete implements IEventListener { public function __construct( private IFilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger ) { } @@ -56,6 +58,7 @@ public function handle(Event $event): void { $this->filesMetadataManager->deleteMetadata($nodeId); } } catch (Exception $e) { + $this->logger->warning('issue while running MetadataDelete', ['exception' => $e]); } } } diff --git a/lib/private/FilesMetadata/Listener/MetadataUpdate.php b/lib/private/FilesMetadata/Listener/MetadataUpdate.php index 64c8bb474b15f..395a852e9e390 100644 --- a/lib/private/FilesMetadata/Listener/MetadataUpdate.php +++ b/lib/private/FilesMetadata/Listener/MetadataUpdate.php @@ -31,6 +31,7 @@ use OCP\Files\Events\Node\NodeCreatedEvent; use OCP\Files\Events\Node\NodeWrittenEvent; use OCP\FilesMetadata\IFilesMetadataManager; +use Psr\Log\LoggerInterface; /** * Handle file creation/modification events and initiate a new event related to the created/edited file. @@ -42,6 +43,7 @@ class MetadataUpdate implements IEventListener { public function __construct( private IFilesMetadataManager $filesMetadataManager, + private LoggerInterface $logger ) { } @@ -56,6 +58,7 @@ public function handle(Event $event): void { try { $this->filesMetadataManager->refreshMetadata($event->getNode()); } catch (Exception $e) { + $this->logger->warning('issue while running MetadataUpdate', ['exception' => $e]); } } } diff --git a/lib/public/Files/Search/ISearchComparison.php b/lib/public/Files/Search/ISearchComparison.php index 068a7e4c69975..f0b4454305480 100644 --- a/lib/public/Files/Search/ISearchComparison.php +++ b/lib/public/Files/Search/ISearchComparison.php @@ -44,7 +44,7 @@ interface ISearchComparison extends ISearchOperator { * @return string * @since 12.0.0 */ - public function getType(); + public function getType(): string; /** * Get the name of the field to compare with @@ -54,24 +54,7 @@ public function getType(); * @return string * @since 12.0.0 */ - public function getField(); - - - /** - * extra means data are not related to the main files table - * - * @return string - * @since 28.0.0 - */ - public function getExtra(): string; - - /** - * returns if data are 'extra' or not - * - * @return bool - * @since 28.0.0 - */ - public function isExtra(): bool; + public function getField(): string; /** * Get the value to compare the field with @@ -79,5 +62,5 @@ public function isExtra(): bool; * @return string|integer|\DateTime * @since 12.0.0 */ - public function getValue(); + public function getValue(): string|int|\DateTime; } diff --git a/lib/public/Files/Search/ISearchOrder.php b/lib/public/Files/Search/ISearchOrder.php index bcb927e73db7c..1bf991ec36844 100644 --- a/lib/public/Files/Search/ISearchOrder.php +++ b/lib/public/Files/Search/ISearchOrder.php @@ -49,23 +49,6 @@ public function getDirection(): string; */ public function getField(): string; - /** - * extra means data are not related to the main files table - * - * @return string - * @since 28.0.0 - */ - public function getExtra(): string; - - /** - * returns if data are 'extra' or not - * - * @return bool - * @since 28.0.0 - */ - public function isExtra(): bool; - - /** * Apply the sorting on 2 FileInfo objects * diff --git a/lib/public/FilesMetadata/IFilesMetadataManager.php b/lib/public/FilesMetadata/IFilesMetadataManager.php index 7ba8cac795a24..1cd0fcb412587 100644 --- a/lib/public/FilesMetadata/IFilesMetadataManager.php +++ b/lib/public/FilesMetadata/IFilesMetadataManager.php @@ -38,10 +38,9 @@ * @since 28.0.0 */ interface IFilesMetadataManager { - /** - * @since 28.0.0 - */ + /** @since 28.0.0 */ public const PROCESS_LIVE = 1; + /** @since 28.0.0 */ public const PROCESS_BACKGROUND = 2; /** @@ -128,10 +127,13 @@ public function getKnownMetadata(): IFilesMetadata; /** * initiate a metadata key with its type. * The call is mandatory before using the metadata property in a webdav request. + * It is not needed to only use this method when the app is enabled: the method can be + * called each time during the app loading as the metadata will only be initiated if not known * * @param string $key metadata key * @param string $type metadata type + * @param bool $indexed TRUE if metadata can be search * @since 28.0.0 */ - public function initMetadataIndex(string $key, string $type): void; + public function initMetadata(string $key, string $type, bool $indexed): void; } diff --git a/lib/public/FilesMetadata/Model/IMetadataQuery.php b/lib/public/FilesMetadata/Model/IMetadataQuery.php index 3e68b47f822f1..d3f55ce6ccee9 100644 --- a/lib/public/FilesMetadata/Model/IMetadataQuery.php +++ b/lib/public/FilesMetadata/Model/IMetadataQuery.php @@ -31,6 +31,7 @@ * @since 28.0.0 */ interface IMetadataQuery { + /** @since 28.0.0 */ public const EXTRA = 'metadata'; /**