Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/server.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/apps/dav
diff options
context:
space:
mode:
authorCarl Schwan <carl@carlschwan.eu>2022-04-05 00:15:00 +0300
committerCarl Schwan <carl@carlschwan.eu>2022-04-13 15:06:29 +0300
commit781784553889601d02553931aed8ff1fde95640b (patch)
tree21dd1b23c192d23be1ab1f468ff77165b7591172 /apps/dav
parentcd95fce105fe5f0e71b1bcac7685464f936b9749 (diff)
Add a metadata service to store file metadata
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
Diffstat (limited to 'apps/dav')
-rw-r--r--apps/dav/composer/autoload.php5
-rw-r--r--apps/dav/composer/composer/autoload_real.php2
-rw-r--r--apps/dav/composer/composer/installed.php4
-rw-r--r--apps/dav/lib/Connector/Sabre/Directory.php5
-rw-r--r--apps/dav/lib/Connector/Sabre/File.php16
-rw-r--r--apps/dav/lib/Connector/Sabre/FilesPlugin.php53
-rw-r--r--apps/dav/lib/Files/FileSearchBackend.php41
-rw-r--r--apps/dav/lib/Files/LazySearchBackend.php24
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);
}
}
}