diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/dav/composer/autoload.php | 5 | ||||
-rw-r--r-- | apps/dav/composer/composer/autoload_real.php | 2 | ||||
-rw-r--r-- | apps/dav/composer/composer/installed.php | 4 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/Directory.php | 5 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/File.php | 16 | ||||
-rw-r--r-- | apps/dav/lib/Connector/Sabre/FilesPlugin.php | 53 | ||||
-rw-r--r-- | apps/dav/lib/Files/FileSearchBackend.php | 41 | ||||
-rw-r--r-- | apps/dav/lib/Files/LazySearchBackend.php | 24 |
8 files changed, 131 insertions, 19 deletions
diff --git a/apps/dav/composer/autoload.php b/apps/dav/composer/autoload.php index 06b2e993e94..a3040af8caa 100644 --- a/apps/dav/composer/autoload.php +++ b/apps/dav/composer/autoload.php @@ -2,6 +2,11 @@ // autoload.php @generated by Composer +if (PHP_VERSION_ID < 50600) { + echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + exit(1); +} + require_once __DIR__ . '/composer/autoload_real.php'; return ComposerAutoloaderInitDAV::getLoader(); diff --git a/apps/dav/composer/composer/autoload_real.php b/apps/dav/composer/composer/autoload_real.php index 8416efa9d7e..4b2290344f5 100644 --- a/apps/dav/composer/composer/autoload_real.php +++ b/apps/dav/composer/composer/autoload_real.php @@ -27,7 +27,7 @@ class ComposerAutoloaderInitDAV spl_autoload_unregister(array('ComposerAutoloaderInitDAV', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - \Composer\Autoload\ComposerStaticInitDAV::getInitializer($loader)(); + call_user_func(\Composer\Autoload\ComposerStaticInitDAV::getInitializer($loader)); $loader->setClassMapAuthoritative(true); $loader->register(true); diff --git a/apps/dav/composer/composer/installed.php b/apps/dav/composer/composer/installed.php index baf72c4fb34..628db5d793b 100644 --- a/apps/dav/composer/composer/installed.php +++ b/apps/dav/composer/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'e2c675724fc4ea50f1275bf0027b96f277c32578', + 'reference' => '9586920c0ec4016864a2219e838fb272127822d8', 'name' => '__root__', 'dev' => false, ), @@ -16,7 +16,7 @@ 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'e2c675724fc4ea50f1275bf0027b96f277c32578', + 'reference' => '9586920c0ec4016864a2219e838fb272127822d8', 'dev_requirement' => false, ), ), diff --git a/apps/dav/lib/Connector/Sabre/Directory.php b/apps/dav/lib/Connector/Sabre/Directory.php index 8b616b0cb8a..9e0b89596cd 100644 --- a/apps/dav/lib/Connector/Sabre/Directory.php +++ b/apps/dav/lib/Connector/Sabre/Directory.php @@ -34,6 +34,8 @@ namespace OCA\DAV\Connector\Sabre; use OC\Files\Mount\MoveableMount; use OC\Files\View; +use OC\Metadata\FileMetadata; +use OC\Metadata\MetadataGroup; use OCA\DAV\Connector\Sabre\Exception\FileLocked; use OCA\DAV\Connector\Sabre\Exception\Forbidden; use OCA\DAV\Connector\Sabre\Exception\InvalidPath; @@ -73,6 +75,9 @@ class Directory extends \OCA\DAV\Connector\Sabre\Node implements \Sabre\DAV\ICol */ private $tree; + /** @var array<string, array<int, FileMetadata>> */ + private array $metadata = []; + /** * Sets up the node, expects a full path name * diff --git a/apps/dav/lib/Connector/Sabre/File.php b/apps/dav/lib/Connector/Sabre/File.php index a46ca372be7..6c379984995 100644 --- a/apps/dav/lib/Connector/Sabre/File.php +++ b/apps/dav/lib/Connector/Sabre/File.php @@ -43,6 +43,7 @@ use OC\AppFramework\Http\Request; use OC\Files\Filesystem; use OC\Files\Stream\HashWrapper; use OC\Files\View; +use OC\Metadata\FileMetadata; use OCA\DAV\AppInfo\Application; use OCA\DAV\Connector\Sabre\Exception\EntityTooLarge; use OCA\DAV\Connector\Sabre\Exception\FileLocked; @@ -80,6 +81,9 @@ class File extends Node implements IFile { protected IL10N $l10n; + /** @var array<string, FileMetadata> */ + private array $metadata = []; + /** * Sets up the node, expects a full path name * @@ -757,4 +761,16 @@ class File extends Node implements IFile { public function getNode(): \OCP\Files\File { return $this->node; } + + public function getMetadata(string $group): FileMetadata { + return $this->metadata[$group]; + } + + public function setMetadata(string $group, FileMetadata $metadata): void { + $this->metadata[$group] = $metadata; + } + + public function hasMetadata(string $group) { + return array_key_exists($group, $this->metadata); + } } diff --git a/apps/dav/lib/Connector/Sabre/FilesPlugin.php b/apps/dav/lib/Connector/Sabre/FilesPlugin.php index 180f05c0e7e..5cc562e0ff8 100644 --- a/apps/dav/lib/Connector/Sabre/FilesPlugin.php +++ b/apps/dav/lib/Connector/Sabre/FilesPlugin.php @@ -34,6 +34,7 @@ namespace OCA\DAV\Connector\Sabre; use OC\AppFramework\Http\Request; +use OC\Metadata\IMetadataManager; use OCP\Constants; use OCP\Files\ForbiddenException; use OCP\Files\StorageNotAvailableException; @@ -41,6 +42,7 @@ use OCP\IConfig; use OCP\IPreview; use OCP\IRequest; use OCP\IUserSession; +use Psr\Log\LoggerInterface; use Sabre\DAV\Exception\Forbidden; use Sabre\DAV\Exception\NotFound; use Sabre\DAV\IFile; @@ -50,6 +52,7 @@ use Sabre\DAV\ServerPlugin; use Sabre\DAV\Tree; use Sabre\HTTP\RequestInterface; use Sabre\HTTP\ResponseInterface; +use Sabre\Uri; class FilesPlugin extends ServerPlugin { @@ -79,6 +82,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_SIZE = '{http://nextcloud.org/ns}file-metadata-size'; /** * Reference to main server object @@ -436,6 +440,29 @@ class FilesPlugin extends ServerPlugin { $propFind->handle(self::UPLOAD_TIME_PROPERTYNAME, function () use ($node) { return $node->getFileInfo()->getUploadTime(); }); + + if ($this->config->getSystemValueBool('enable_file_metadata', true)) { + $propFind->handle(self::FILE_METADATA_SIZE, function () use ($node) { + if (!str_starts_with($node->getFileInfo()->getMimetype(), 'image')) { + return json_encode([]); + } + + if ($node->hasMetadata('size')) { + $sizeMetadata = $node->getMetadata('size'); + } else { + // This code path should not be called since we try to preload + // the metadata when loading the folder or the search results + // in one go + $metadataManager = \OC::$server->get(IMetadataManager::class); + $sizeMetadata = $metadataManager->fetchMetadataFor('size', [$node->getId()])[$node->getId()]; + + // TODO would be nice to display this in the profiler... + \OC::$server->get(LoggerInterface::class)->warning('Inefficient fetching of metadata'); + } + + return json_encode($sizeMetadata->getMetadata()); + }); + } } if ($node instanceof Directory) { @@ -448,6 +475,32 @@ class FilesPlugin extends ServerPlugin { }); $requestProperties = $propFind->getRequestedProperties(); + + // TODO detect dynamically which metadata groups are requested and + // preload all of them and not just size + if ($this->config->getSystemValueBool('enable_file_metadata', true) + && in_array(self::FILE_METADATA_SIZE, $requestProperties, true)) { + // Preloading of the metadata + $fileIds = []; + foreach ($node->getChildren() as $child) { + /** @var \OCP\Files\Node|Node $child */ + if (str_starts_with($child->getFileInfo()->getMimeType(), 'image/')) { + /** @var File $child */ + $fileIds[] = $child->getFileInfo()->getId(); + } + } + /** @var IMetaDataManager $metadataManager */ + $metadataManager = \OC::$server->get(IMetadataManager::class); + $preloadedMetadata = $metadataManager->fetchMetadataFor('size', $fileIds); + foreach ($node->getChildren() as $child) { + /** @var \OCP\Files\Node|Node $child */ + if (str_starts_with($child->getFileInfo()->getMimeType(), 'image')) { + /** @var File $child */ + $child->setMetadata('size', $preloadedMetadata[$child->getFileInfo()->getId()]); + } + } + } + if (in_array(self::SUBFILE_COUNT_PROPERTYNAME, $requestProperties, true) || in_array(self::SUBFOLDER_COUNT_PROPERTYNAME, $requestProperties, true)) { $nbFiles = 0; diff --git a/apps/dav/lib/Files/FileSearchBackend.php b/apps/dav/lib/Files/FileSearchBackend.php index 45e911db182..21eb14a29bd 100644 --- a/apps/dav/lib/Files/FileSearchBackend.php +++ b/apps/dav/lib/Files/FileSearchBackend.php @@ -30,6 +30,7 @@ use OC\Files\Search\SearchComparison; use OC\Files\Search\SearchOrder; use OC\Files\Search\SearchQuery; use OC\Files\View; +use OC\Metadata\IMetadataManager; use OCA\DAV\Connector\Sabre\CachingTree; use OCA\DAV\Connector\Sabre\Directory; use OCA\DAV\Connector\Sabre\FilesPlugin; @@ -44,6 +45,7 @@ use OCP\Files\Search\ISearchQuery; use OCP\IUser; use OCP\Share\IManager; use Sabre\DAV\Exception\NotFound; +use Sabre\DAV\INode; use SearchDAV\Backend\ISearchBackend; use SearchDAV\Backend\SearchPropertyDefinition; use SearchDAV\Backend\SearchResult; @@ -88,14 +90,12 @@ class FileSearchBackend implements ISearchBackend { /** * Search endpoint will be remote.php/dav - * - * @return string */ - public function getArbiterPath() { + public function getArbiterPath(): string { return ''; } - public function isValidScope($href, $depth, $path) { + public function isValidScope(string $href, $depth, ?string $path): bool { // only allow scopes inside the dav server if (is_null($path)) { return false; @@ -109,7 +109,7 @@ class FileSearchBackend implements ISearchBackend { } } - public function getPropertyDefinitionsForScope($href, $path) { + public function getPropertyDefinitionsForScope(string $href, ?string $path): array { // all valid scopes support the same schema //todo dynamically load all propfind properties that are supported @@ -132,15 +132,44 @@ class FileSearchBackend implements ISearchBackend { new SearchPropertyDefinition(FilesPlugin::OWNER_DISPLAY_NAME_PROPERTYNAME, false, true, false), new SearchPropertyDefinition(FilesPlugin::DATA_FINGERPRINT_PROPERTYNAME, false, true, false), new SearchPropertyDefinition(FilesPlugin::HAS_PREVIEW_PROPERTYNAME, false, true, false, SearchPropertyDefinition::DATATYPE_BOOLEAN), + new SearchPropertyDefinition(FilesPlugin::FILE_METADATA_SIZE, false, true, false, SearchPropertyDefinition::DATATYPE_STRING), new SearchPropertyDefinition(FilesPlugin::FILEID_PROPERTYNAME, false, true, false, SearchPropertyDefinition::DATATYPE_NONNEGATIVE_INTEGER), ]; } /** + * @param INode[] $nodes + * @param string[] $requestProperties + */ + public function preloadPropertyFor(array $nodes, array $requestProperties): void { + if (in_array(FilesPlugin::FILE_METADATA_SIZE, $requestProperties, true)) { + // Preloading of the metadata + $fileIds = []; + foreach ($nodes as $node) { + /** @var \OCP\Files\Node|\OCA\DAV\Connector\Sabre\Node $node */ + if (str_starts_with($node->getFileInfo()->getMimeType(), 'image/')) { + /** @var \OCA\DAV\Connector\Sabre\File $node */ + $fileIds[] = $node->getFileInfo()->getId(); + } + } + /** @var IMetaDataManager $metadataManager */ + $metadataManager = \OC::$server->get(IMetadataManager::class); + $preloadedMetadata = $metadataManager->fetchMetadataFor('size', $fileIds); + foreach ($nodes as $node) { + /** @var \OCP\Files\Node|\OCA\DAV\Connector\Sabre\Node $node */ + if (str_starts_with($node->getFileInfo()->getMimeType(), 'image/')) { + /** @var \OCA\DAV\Connector\Sabre\File $node */ + $node->setMetadata('size', $preloadedMetadata[$node->getFileInfo()->getId()]); + } + } + } + } + + /** * @param Query $search * @return SearchResult[] */ - public function search(Query $search) { + public function search(Query $search): array { if (count($search->from) !== 1) { throw new \InvalidArgumentException('Searching more than one folder is not supported'); } diff --git a/apps/dav/lib/Files/LazySearchBackend.php b/apps/dav/lib/Files/LazySearchBackend.php index d84c11306e3..c3b2f27d72a 100644 --- a/apps/dav/lib/Files/LazySearchBackend.php +++ b/apps/dav/lib/Files/LazySearchBackend.php @@ -22,6 +22,7 @@ */ namespace OCA\DAV\Files; +use Sabre\DAV\INode; use SearchDAV\Backend\ISearchBackend; use SearchDAV\Query\Query; @@ -35,7 +36,7 @@ class LazySearchBackend implements ISearchBackend { $this->backend = $backend; } - public function getArbiterPath() { + public function getArbiterPath(): string { if ($this->backend) { return $this->backend->getArbiterPath(); } else { @@ -43,27 +44,30 @@ class LazySearchBackend implements ISearchBackend { } } - public function isValidScope($href, $depth, $path) { + public function isValidScope(string $href, $depth, ?string $path): bool { if ($this->backend) { return $this->backend->getArbiterPath(); - } else { - return false; } + return false; } - public function getPropertyDefinitionsForScope($href, $path) { + public function getPropertyDefinitionsForScope(string $href, ?String $path): array { if ($this->backend) { return $this->backend->getPropertyDefinitionsForScope($href, $path); - } else { - return []; } + return []; } - public function search(Query $query) { + public function search(Query $query): array { if ($this->backend) { return $this->backend->search($query); - } else { - return []; + } + return []; + } + + public function preloadPropertyFor(array $nodes, array $requestProperties): void { + if ($this->backend) { + $this->backend->preloadPropertyFor($nodes, $requestProperties); } } } |