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/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/composer/composer/InstalledVersions.php4
-rw-r--r--lib/composer/composer/LICENSE2
-rw-r--r--lib/composer/composer/autoload_classmap.php11
-rw-r--r--lib/composer/composer/autoload_namespaces.php2
-rw-r--r--lib/composer/composer/autoload_psr4.php2
-rw-r--r--lib/composer/composer/autoload_real.php25
-rw-r--r--lib/composer/composer/autoload_static.php9
-rw-r--r--lib/composer/composer/installed.php4
-rw-r--r--lib/private/Files/ObjectStore/NoopScanner.php2
-rw-r--r--lib/private/Metadata/Capabilities.php44
-rw-r--r--lib/private/Metadata/FileEventListener.php84
-rw-r--r--lib/private/Metadata/FileMetadata.php43
-rw-r--r--lib/private/Metadata/FileMetadataMapper.php105
-rw-r--r--lib/private/Metadata/IMetadataManager.php35
-rw-r--r--lib/private/Metadata/IMetadataProvider.php41
-rw-r--r--lib/private/Metadata/MetadataManager.php100
-rw-r--r--lib/private/Metadata/Provider/ExifProvider.php51
-rw-r--r--lib/private/Server.php12
-rw-r--r--lib/public/AppFramework/Db/Entity.php4
-rw-r--r--lib/public/AppFramework/Db/QBMapper.php2
-rw-r--r--lib/public/DB/QueryBuilder/IQueryBuilder.php5
-rw-r--r--lib/public/DB/Types.php6
22 files changed, 576 insertions, 17 deletions
diff --git a/lib/composer/composer/InstalledVersions.php b/lib/composer/composer/InstalledVersions.php
index d50e0c9fcc4..fc50a9f8622 100644
--- a/lib/composer/composer/InstalledVersions.php
+++ b/lib/composer/composer/InstalledVersions.php
@@ -264,7 +264,7 @@ class InstalledVersions
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
- if (substr(__DIR__, -8, 1) !== 'C') {
+ if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
self::$installed = include __DIR__ . '/installed.php';
} else {
self::$installed = array();
@@ -337,7 +337,7 @@ class InstalledVersions
if (null === self::$installed) {
// only require the installed.php file if this file is loaded from its dumped location,
// and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
- if (substr(__DIR__, -8, 1) !== 'C') {
+ if (substr(__DIR__, -8, 1) !== 'C' && is_file(__DIR__ . '/installed.php')) {
self::$installed = require __DIR__ . '/installed.php';
} else {
self::$installed = array();
diff --git a/lib/composer/composer/LICENSE b/lib/composer/composer/LICENSE
index f27399a042d..62ecfd8d004 100644
--- a/lib/composer/composer/LICENSE
+++ b/lib/composer/composer/LICENSE
@@ -1,4 +1,3 @@
-
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -18,4 +17,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index acc0f6bf2ad..be40cd4c607 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
-$vendorDir = dirname(__DIR__);
+$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
@@ -1021,6 +1021,7 @@ return array(
'OC\\Core\\Migrations\\Version23000Date20211203110726' => $baseDir . '/core/Migrations/Version23000Date20211203110726.php',
'OC\\Core\\Migrations\\Version23000Date20211213203940' => $baseDir . '/core/Migrations/Version23000Date20211213203940.php',
'OC\\Core\\Migrations\\Version240000Date20220202150027' => $baseDir . '/core/Migrations/Version240000Date20220202150027.php',
+ 'OC\\Core\\Migrations\\Version240000Date20220404230027' => $baseDir . '/core/Migrations/Version240000Date20220404230027.php',
'OC\\Core\\Migrations\\Version24000Date20211210141942' => $baseDir . '/core/Migrations/Version24000Date20211210141942.php',
'OC\\Core\\Migrations\\Version24000Date20211213081506' => $baseDir . '/core/Migrations/Version24000Date20211213081506.php',
'OC\\Core\\Migrations\\Version24000Date20211213081604' => $baseDir . '/core/Migrations/Version24000Date20211213081604.php',
@@ -1302,6 +1303,14 @@ return array(
'OC\\Memcache\\ProfilerWrapperCache' => $baseDir . '/lib/private/Memcache/ProfilerWrapperCache.php',
'OC\\Memcache\\Redis' => $baseDir . '/lib/private/Memcache/Redis.php',
'OC\\MemoryInfo' => $baseDir . '/lib/private/MemoryInfo.php',
+ 'OC\\Metadata\\Capabilities' => $baseDir . '/lib/private/Metadata/Capabilities.php',
+ 'OC\\Metadata\\FileEventListener' => $baseDir . '/lib/private/Metadata/FileEventListener.php',
+ 'OC\\Metadata\\FileMetadata' => $baseDir . '/lib/private/Metadata/FileMetadata.php',
+ 'OC\\Metadata\\FileMetadataMapper' => $baseDir . '/lib/private/Metadata/FileMetadataMapper.php',
+ 'OC\\Metadata\\IMetadataManager' => $baseDir . '/lib/private/Metadata/IMetadataManager.php',
+ 'OC\\Metadata\\IMetadataProvider' => $baseDir . '/lib/private/Metadata/IMetadataProvider.php',
+ 'OC\\Metadata\\MetadataManager' => $baseDir . '/lib/private/Metadata/MetadataManager.php',
+ 'OC\\Metadata\\Provider\\ExifProvider' => $baseDir . '/lib/private/Metadata/Provider/ExifProvider.php',
'OC\\Migration\\BackgroundRepair' => $baseDir . '/lib/private/Migration/BackgroundRepair.php',
'OC\\Migration\\ConsoleOutput' => $baseDir . '/lib/private/Migration/ConsoleOutput.php',
'OC\\Migration\\SimpleOutput' => $baseDir . '/lib/private/Migration/SimpleOutput.php',
diff --git a/lib/composer/composer/autoload_namespaces.php b/lib/composer/composer/autoload_namespaces.php
index f1ae7a0ffec..4a9c20beed0 100644
--- a/lib/composer/composer/autoload_namespaces.php
+++ b/lib/composer/composer/autoload_namespaces.php
@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
-$vendorDir = dirname(__DIR__);
+$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
diff --git a/lib/composer/composer/autoload_psr4.php b/lib/composer/composer/autoload_psr4.php
index 74e48cf69ae..b641d9c6a03 100644
--- a/lib/composer/composer/autoload_psr4.php
+++ b/lib/composer/composer/autoload_psr4.php
@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
-$vendorDir = dirname(__DIR__);
+$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname(dirname($vendorDir));
return array(
diff --git a/lib/composer/composer/autoload_real.php b/lib/composer/composer/autoload_real.php
index 4b1ab7678ec..a5748c7a891 100644
--- a/lib/composer/composer/autoload_real.php
+++ b/lib/composer/composer/autoload_real.php
@@ -23,11 +23,30 @@ class ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c
}
spl_autoload_register(array('ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c', 'loadClassLoader'), true, true);
- self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
spl_autoload_unregister(array('ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c', 'loadClassLoader'));
- require __DIR__ . '/autoload_static.php';
- \Composer\Autoload\ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::getInitializer($loader)();
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
+ if ($useStaticLoader) {
+ require __DIR__ . '/autoload_static.php';
+
+ call_user_func(\Composer\Autoload\ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::getInitializer($loader));
+ } else {
+ $map = require __DIR__ . '/autoload_namespaces.php';
+ foreach ($map as $namespace => $path) {
+ $loader->set($namespace, $path);
+ }
+
+ $map = require __DIR__ . '/autoload_psr4.php';
+ foreach ($map as $namespace => $path) {
+ $loader->setPsr4($namespace, $path);
+ }
+
+ $classMap = require __DIR__ . '/autoload_classmap.php';
+ if ($classMap) {
+ $loader->addClassMap($classMap);
+ }
+ }
$loader->register(true);
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 09e8d3a627e..7e778d73b83 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -1050,6 +1050,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Migrations\\Version23000Date20211203110726' => __DIR__ . '/../../..' . '/core/Migrations/Version23000Date20211203110726.php',
'OC\\Core\\Migrations\\Version23000Date20211213203940' => __DIR__ . '/../../..' . '/core/Migrations/Version23000Date20211213203940.php',
'OC\\Core\\Migrations\\Version240000Date20220202150027' => __DIR__ . '/../../..' . '/core/Migrations/Version240000Date20220202150027.php',
+ 'OC\\Core\\Migrations\\Version240000Date20220404230027' => __DIR__ . '/../../..' . '/core/Migrations/Version240000Date20220404230027.php',
'OC\\Core\\Migrations\\Version24000Date20211210141942' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211210141942.php',
'OC\\Core\\Migrations\\Version24000Date20211213081506' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211213081506.php',
'OC\\Core\\Migrations\\Version24000Date20211213081604' => __DIR__ . '/../../..' . '/core/Migrations/Version24000Date20211213081604.php',
@@ -1331,6 +1332,14 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Memcache\\ProfilerWrapperCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/ProfilerWrapperCache.php',
'OC\\Memcache\\Redis' => __DIR__ . '/../../..' . '/lib/private/Memcache/Redis.php',
'OC\\MemoryInfo' => __DIR__ . '/../../..' . '/lib/private/MemoryInfo.php',
+ 'OC\\Metadata\\Capabilities' => __DIR__ . '/../../..' . '/lib/private/Metadata/Capabilities.php',
+ 'OC\\Metadata\\FileEventListener' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileEventListener.php',
+ 'OC\\Metadata\\FileMetadata' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileMetadata.php',
+ 'OC\\Metadata\\FileMetadataMapper' => __DIR__ . '/../../..' . '/lib/private/Metadata/FileMetadataMapper.php',
+ 'OC\\Metadata\\IMetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataManager.php',
+ 'OC\\Metadata\\IMetadataProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataProvider.php',
+ 'OC\\Metadata\\MetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/MetadataManager.php',
+ 'OC\\Metadata\\Provider\\ExifProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/Provider/ExifProvider.php',
'OC\\Migration\\BackgroundRepair' => __DIR__ . '/../../..' . '/lib/private/Migration/BackgroundRepair.php',
'OC\\Migration\\ConsoleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/ConsoleOutput.php',
'OC\\Migration\\SimpleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/SimpleOutput.php',
diff --git a/lib/composer/composer/installed.php b/lib/composer/composer/installed.php
index f12a8e00dbe..67a1ddfbd8c 100644
--- a/lib/composer/composer/installed.php
+++ b/lib/composer/composer/installed.php
@@ -5,7 +5,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../../../',
'aliases' => array(),
- 'reference' => '1225189f74d06606aafc4150d07584b90cea50dd',
+ 'reference' => '42c7886f80c7a5e767b192d07474114dd0848b16',
'name' => '__root__',
'dev' => false,
),
@@ -16,7 +16,7 @@
'type' => 'library',
'install_path' => __DIR__ . '/../../../',
'aliases' => array(),
- 'reference' => '1225189f74d06606aafc4150d07584b90cea50dd',
+ 'reference' => '42c7886f80c7a5e767b192d07474114dd0848b16',
'dev_requirement' => false,
),
),
diff --git a/lib/private/Files/ObjectStore/NoopScanner.php b/lib/private/Files/ObjectStore/NoopScanner.php
index 42e212271d5..3b8cbdb18bb 100644
--- a/lib/private/Files/ObjectStore/NoopScanner.php
+++ b/lib/private/Files/ObjectStore/NoopScanner.php
@@ -31,7 +31,7 @@ use OC\Files\Storage\Storage;
class NoopScanner extends Scanner {
public function __construct(Storage $storage) {
- //we don't need the storage, so do nothing here
+ // we don't need the storage, so do nothing here
}
/**
diff --git a/lib/private/Metadata/Capabilities.php b/lib/private/Metadata/Capabilities.php
new file mode 100644
index 00000000000..2fa0006f581
--- /dev/null
+++ b/lib/private/Metadata/Capabilities.php
@@ -0,0 +1,44 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ * @license AGPL-3.0-or-later
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Metadata;
+
+use OCP\Capabilities\IPublicCapability;
+use OCP\IConfig;
+
+class Capabilities implements IPublicCapability {
+ private IMetadataManager $manager;
+ private IConfig $config;
+
+ public function __construct(IMetadataManager $manager, IConfig $config) {
+ $this->manager = $manager;
+ $this->config = $config;
+ }
+
+ public function getCapabilities() {
+ if ($this->config->getSystemValueBool('enable_file_metadata', true)) {
+ return ['metadataAvailable' => $this->manager->getCapabilities()];
+ }
+
+ return [];
+ }
+}
diff --git a/lib/private/Metadata/FileEventListener.php b/lib/private/Metadata/FileEventListener.php
new file mode 100644
index 00000000000..fdec891c6e2
--- /dev/null
+++ b/lib/private/Metadata/FileEventListener.php
@@ -0,0 +1,84 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ * @license AGPL-3.0-or-later
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Metadata;
+
+use OC\Files\Filesystem;
+use OCP\EventDispatcher\Event;
+use OCP\EventDispatcher\IEventListener;
+use OCP\Files\Events\Node\NodeDeletedEvent;
+use OCP\Files\Events\Node\NodeWrittenEvent;
+use OCP\Files\Events\NodeRemovedFromCache;
+use OCP\Files\File;
+use OCP\Files\Node;
+use OCP\Files\NotFoundException;
+use OCP\Files\FileInfo;
+
+class FileEventListener implements IEventListener {
+ private IMetadataManager $manager;
+
+ public function __construct(IMetadataManager $manager) {
+ $this->manager = $manager;
+ }
+
+ private function shouldExtractMetadata(Node $node): bool {
+ try {
+ if ($node->getMimetype() === 'httpd/unix-directory') {
+ return false;
+ }
+ } catch (NotFoundException $e) {
+ return false;
+ }
+ if ($node->getSize(false) <= 0) {
+ return false;
+ }
+
+ $path = $node->getPath();
+ // TODO make this more dynamic, we have the same issue in other places
+ return !str_starts_with($path, 'appdata_') && !str_starts_with($path, 'files_versions/') && !str_starts_with($path, 'files_trashbin/');
+ }
+
+ public function handle(Event $event): void {
+ if ($event instanceof NodeRemovedFromCache) {
+ $view = Filesystem::getView();
+ $info = $view->getFileInfo($event->getPath());
+ if ($info && $info->getType() === FileInfo::TYPE_FILE) {
+ $this->manager->clearMetadata($info->getId());
+ }
+ }
+
+ if ($event instanceof NodeDeletedEvent) {
+ $node = $event->getNode();
+ if ($this->shouldExtractMetadata($node)) {
+ /** @var File $node */
+ $this->manager->clearMetadata($event->getNode()->getId());
+ }
+ }
+
+ if ($event instanceof NodeWrittenEvent) {
+ $node = $event->getNode();
+ if ($this->shouldExtractMetadata($node)) {
+ /** @var File $node */
+ $this->manager->generateMetadata($event->getNode(), false);
+ }
+ }
+ }
+}
diff --git a/lib/private/Metadata/FileMetadata.php b/lib/private/Metadata/FileMetadata.php
new file mode 100644
index 00000000000..c53f5d7f619
--- /dev/null
+++ b/lib/private/Metadata/FileMetadata.php
@@ -0,0 +1,43 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Metadata;
+
+use OCP\AppFramework\Db\Entity;
+use OCP\DB\Types;
+
+/**
+ * @method string getGroupName()
+ * @method void setGroupName(string $groupName)
+ * @method string getMetadata()
+ * @method void setMetadata(array $metadata)
+ * @see OC\Core\Migrations\Version240000Date20220404230027
+ */
+class FileMetadata extends Entity {
+ protected ?string $groupName = null;
+ protected ?array $metadata = null;
+
+ public function __construct() {
+ $this->addType('groupName', 'string');
+ $this->addType('metadata', Types::JSON);
+ }
+}
diff --git a/lib/private/Metadata/FileMetadataMapper.php b/lib/private/Metadata/FileMetadataMapper.php
new file mode 100644
index 00000000000..53f750ae540
--- /dev/null
+++ b/lib/private/Metadata/FileMetadataMapper.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ * @license AGPL-3.0-or-later
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Metadata;
+
+use OCP\AppFramework\Db\DoesNotExistException;
+use OCP\AppFramework\Db\MultipleObjectsReturnedException;
+use OCP\AppFramework\Db\QBMapper;
+use OCP\DB\Exception;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\IDBConnection;
+
+class FileMetadataMapper extends QBMapper {
+ public function __construct(IDBConnection $db) {
+ parent::__construct($db, 'file_metadata', FileMetadata::class);
+ }
+
+ /**
+ * @return FileMetadata[]
+ * @throws Exception
+ */
+ public function findForFile(int $fileId): array {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
+
+ return $this->findEntities($qb);
+ }
+
+ /**
+ * @throws DoesNotExistException
+ * @throws MultipleObjectsReturnedException
+ * @throws Exception
+ */
+ public function findForGroupForFile(int $fileId, string $groupName): FileMetadata {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT_ARRAY)))
+ ->andWhere($qb->expr()->eq('group_name', $qb->createNamedParameter($groupName, IQueryBuilder::PARAM_STR)));
+
+ return $this->findEntity($qb);
+ }
+
+ /**
+ * @return array<int, FileMetadata>
+ * @throws Exception
+ */
+ public function findForGroupForFiles(array $fileIds, string $groupName): array {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->in('id', $qb->createParameter('fileIds')))
+ ->andWhere($qb->expr()->eq('group_name', $qb->createNamedParameter($groupName, IQueryBuilder::PARAM_STR)));
+
+ $metadata = [];
+ foreach (array_chunk($fileIds, 1000) as $fileIdsChunk) {
+ $qb->setParameter('fileIds', $fileIdsChunk, IQueryBuilder::PARAM_INT_ARRAY);
+ /** @var FileMetadata[] $rawEntities */
+ $rawEntities = $this->findEntities($qb);
+ foreach ($rawEntities as $entity) {
+ $metadata[$entity->getId()] = $entity;
+ }
+ }
+
+ foreach ($fileIds as $id) {
+ if (isset($metadata[$id])) {
+ continue;
+ }
+ $empty = new FileMetadata();
+ $empty->setMetadata([]);
+ $empty->setGroupName($groupName);
+ $empty->setId($id);
+ $metadata[$id] = $empty;
+ }
+ return $metadata;
+ }
+
+ public function clear(int $fileId): void {
+ $qb = $this->db->getQueryBuilder();
+ $qb->delete($this->getTableName())
+ ->where($qb->expr()->eq('id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
+
+ $qb->executeStatement();
+ }
+}
diff --git a/lib/private/Metadata/IMetadataManager.php b/lib/private/Metadata/IMetadataManager.php
new file mode 100644
index 00000000000..d2d37f15c25
--- /dev/null
+++ b/lib/private/Metadata/IMetadataManager.php
@@ -0,0 +1,35 @@
+<?php
+
+declare(strict_types=1);
+
+namespace OC\Metadata;
+
+use OCP\Files\File;
+
+/**
+ * Interface to manage additional metadata for files
+ */
+interface IMetadataManager {
+ /**
+ * @param class-string<IMetadataProvider> $className
+ */
+ public function registerProvider(string $className): void;
+
+ /**
+ * Generate the metadata for one file
+ */
+ public function generateMetadata(File $file, bool $checkExisting = false): void;
+
+ /**
+ * Clear the metadata for one file
+ */
+ public function clearMetadata(int $fileId): void;
+
+ /** @return array<int, FileMetadata> */
+ public function fetchMetadataFor(string $group, array $fileIds): array;
+
+ /**
+ * Get the capabilites as an array of mimetype regex to the type provided
+ */
+ public function getCapabilities(): array;
+}
diff --git a/lib/private/Metadata/IMetadataProvider.php b/lib/private/Metadata/IMetadataProvider.php
new file mode 100644
index 00000000000..7cbe102a538
--- /dev/null
+++ b/lib/private/Metadata/IMetadataProvider.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace OC\Metadata;
+
+use OCP\Files\File;
+
+/**
+ * Interface for the metadata providers. If you want an application to provide
+ * some metadata, you can use this to store them.
+ */
+interface IMetadataProvider {
+ /**
+ * The list of groups that this metadata provider is able to provide.
+ *
+ * @return string[]
+ */
+ public static function groupsProvided(): array;
+
+ /**
+ * Check if the metadata provider is available. A metadata provider might be
+ * unavailable due to a php extension not being installed.
+ */
+ public static function isAvailable(): bool;
+
+ /**
+ * Get the mimetypes supported as a regex.
+ */
+ public static function getMimetypesSupported(): string;
+
+ /**
+ * Execute the extraction on the specified file. The metadata should be
+ * grouped by metadata
+ *
+ * Each group should be json serializable and the string representation
+ * shouldn't be longer than 4000 characters.
+ *
+ * @param File $file The file to extract the metadata from
+ * @param array<string, FileMetadata> An array containing all the metadata fetched.
+ */
+ public function execute(File $file): array;
+}
diff --git a/lib/private/Metadata/MetadataManager.php b/lib/private/Metadata/MetadataManager.php
new file mode 100644
index 00000000000..69e9cb3c852
--- /dev/null
+++ b/lib/private/Metadata/MetadataManager.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * @copyright Copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ * @license AGPL-3.0-or-later
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OC\Metadata;
+
+use OC\Metadata\Provider\ExifProvider;
+use OCP\Files\File;
+use OCP\IConfig;
+use Psr\Log\LoggerInterface;
+
+class MetadataManager implements IMetadataManager {
+ /** @var array<string, IMetadataProvider> */
+ private array $providers;
+ private array $providerClasses;
+ private FileMetadataMapper $fileMetadataMapper;
+ private IConfig $config;
+ private LoggerInterface $logger;
+
+ public function __construct(
+ FileMetadataMapper $fileMetadataMapper,
+ IConfig $config,
+ LoggerInterface $logger
+ ) {
+ $this->providers = [];
+ $this->providerClasses = [];
+ $this->fileMetadataMapper = $fileMetadataMapper;
+ $this->config = $config;
+ $this->logger = $logger;
+
+ // TODO move to another place, where?
+ $this->registerProvider(ExifProvider::class);
+ }
+
+ /**
+ * @param class-string<IMetadataProvider> $className
+ */
+ public function registerProvider(string $className):void {
+ if (in_array($className, $this->providerClasses)) {
+ return;
+ }
+
+ if (call_user_func([$className, 'isAvailable'])) {
+ $this->providers[call_user_func([$className, 'getMimetypesSupported'])] = \OC::$server->get($className);
+ }
+ }
+
+ public function generateMetadata(File $file, bool $checkExisting = false): void {
+ $existingMetadataGroups = [];
+
+ if ($checkExisting) {
+ $existingMetadata = $this->fileMetadataMapper->findForFile($file->getId());
+ foreach ($existingMetadata as $metadata) {
+ $existingMetadataGroups[] = $metadata->getGroupName();
+ }
+ }
+
+ foreach ($this->providers as $supportedMimetype => $provider) {
+ if (preg_match($supportedMimetype, $file->getMimeType())) {
+ if (count(array_diff($provider::groupsProvided(), $existingMetadataGroups)) > 0) {
+ $metaDataGroup = $provider->execute($file);
+ foreach ($metaDataGroup as $group => $metadata) {
+ $this->fileMetadataMapper->insertOrUpdate($metadata);
+ }
+ }
+ }
+ }
+ }
+
+ public function clearMetadata(int $fileId): void {
+ $this->fileMetadataMapper->clear($fileId);
+ }
+
+ public function fetchMetadataFor(string $group, array $fileIds): array {
+ return $this->fileMetadataMapper->findForGroupForFiles($fileIds, $group);
+ }
+
+ public function getCapabilities(): array {
+ $capabilities = [];
+ foreach ($this->providers as $supportedMimetype => $provider) {
+ $capabilities[$supportedMimetype] = $provider::groupsProvided();
+ }
+ return $capabilities;
+ }
+}
diff --git a/lib/private/Metadata/Provider/ExifProvider.php b/lib/private/Metadata/Provider/ExifProvider.php
new file mode 100644
index 00000000000..91c858f6794
--- /dev/null
+++ b/lib/private/Metadata/Provider/ExifProvider.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace OC\Metadata\Provider;
+
+use OC\Metadata\FileMetadata;
+use OC\Metadata\IMetadataProvider;
+use OCP\Files\File;
+
+class ExifProvider implements IMetadataProvider {
+ public static function groupsProvided(): array {
+ return ['size'];
+ }
+
+ public static function isAvailable(): bool {
+ return extension_loaded('exif');
+ }
+
+ public function execute(File $file): array {
+ $fileDescriptor = $file->fopen('rb');
+ $data = @exif_read_data($fileDescriptor, 'ANY_TAG', true);
+
+ $size = new FileMetadata();
+ $size->setGroupName('size');
+ $size->setId($file->getId());
+ $size->setMetadata([]);
+
+ if (!$data) {
+ return [
+ 'size' => $size,
+ ];
+ }
+
+ if (array_key_exists('COMPUTED', $data)
+ && array_key_exists('Width', $data['COMPUTED'])
+ && array_key_exists('Height', $data['COMPUTED'])
+ ) {
+ $size->setMetadata([
+ 'width' => $data['COMPUTED']['Width'],
+ 'height' => $data['COMPUTED']['Height'],
+ ]);
+ }
+
+ return [
+ 'size' => $size,
+ ];
+ }
+
+ public static function getMimetypesSupported(): string {
+ return '/image\/.*/';
+ }
+}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 7817d1beafe..e9d673d3746 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -122,6 +122,9 @@ use OC\Log\PsrLoggerAdapter;
use OC\Mail\Mailer;
use OC\Memcache\ArrayCache;
use OC\Memcache\Factory;
+use OC\Metadata\Capabilities as MetadataCapabilities;
+use OC\Metadata\IMetadataManager;
+use OC\Metadata\MetadataManager;
use OC\Notification\Manager;
use OC\OCS\DiscoveryService;
use OC\Preview\GeneratorHelper;
@@ -151,7 +154,6 @@ use OC\Template\JSCombiner;
use OCA\Theming\ImageManager;
use OCA\Theming\ThemingDefaults;
use OCA\Theming\Util;
-use OCA\WorkflowEngine\Service\Logger;
use OCP\Accounts\IAccountManager;
use OCP\App\IAppManager;
use OCP\Authentication\LoginCredentials\IStore;
@@ -241,15 +243,12 @@ use OCP\SystemTag\ISystemTagManager;
use OCP\SystemTag\ISystemTagObjectMapper;
use OCP\Talk\IBroker;
use OCP\User\Events\BeforePasswordUpdatedEvent;
-use OCP\User\Events\BeforeUserCreatedEvent;
-use OCP\User\Events\BeforeUserDeletedEvent;
use OCP\User\Events\BeforeUserLoggedInEvent;
use OCP\User\Events\BeforeUserLoggedInWithCookieEvent;
use OCP\User\Events\BeforeUserLoggedOutEvent;
use OCP\User\Events\PasswordUpdatedEvent;
use OCP\User\Events\PostLoginEvent;
use OCP\User\Events\UserChangedEvent;
-use OCP\User\Events\UserDeletedEvent;
use OCP\User\Events\UserLoggedInEvent;
use OCP\User\Events\UserLoggedInWithCookieEvent;
use OCP\User\Events\UserLoggedOutEvent;
@@ -1163,6 +1162,9 @@ class Server extends ServerContainer implements IServerContainer {
$manager->registerCapability(function () use ($c) {
return $c->get(\OC\Security\Bruteforce\Capabilities::class);
});
+ $manager->registerCapability(function () use ($c) {
+ return $c->get(MetadataCapabilities::class);
+ });
return $manager;
});
/** @deprecated 19.0.0 */
@@ -1433,6 +1435,8 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(IBroker::class, Broker::class);
+ $this->registerAlias(IMetadataManager::class, MetadataManager::class);
+
$this->connectDispatcher();
}
diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php
index 89e8f69859e..a059e3a27b0 100644
--- a/lib/public/AppFramework/Db/Entity.php
+++ b/lib/public/AppFramework/Db/Entity.php
@@ -120,6 +120,10 @@ abstract class Entity {
if (!$args[0] instanceof \DateTime) {
$args[0] = new \DateTime($args[0]);
}
+ } elseif ($type === 'json') {
+ if (!is_array($args[0])) {
+ $args[0] = json_decode($args[0], true);
+ }
} else {
settype($args[0], $type);
}
diff --git a/lib/public/AppFramework/Db/QBMapper.php b/lib/public/AppFramework/Db/QBMapper.php
index 5124650bc19..fa753a09dcf 100644
--- a/lib/public/AppFramework/Db/QBMapper.php
+++ b/lib/public/AppFramework/Db/QBMapper.php
@@ -253,6 +253,8 @@ abstract class QBMapper {
return IQueryBuilder::PARAM_LOB;
case 'datetime':
return IQueryBuilder::PARAM_DATE;
+ case 'json':
+ return IQueryBuilder::PARAM_JSON;
}
return IQueryBuilder::PARAM_STR;
diff --git a/lib/public/DB/QueryBuilder/IQueryBuilder.php b/lib/public/DB/QueryBuilder/IQueryBuilder.php
index 76754f7bf41..afca9e372ee 100644
--- a/lib/public/DB/QueryBuilder/IQueryBuilder.php
+++ b/lib/public/DB/QueryBuilder/IQueryBuilder.php
@@ -65,6 +65,11 @@ interface IQueryBuilder {
public const PARAM_DATE = 'datetime';
/**
+ * @since 24.0.0
+ */
+ public const PARAM_JSON = 'json';
+
+ /**
* @since 9.0.0
*/
public const PARAM_INT_ARRAY = Connection::PARAM_INT_ARRAY;
diff --git a/lib/public/DB/Types.php b/lib/public/DB/Types.php
index 4636ac3389f..31a474b03a0 100644
--- a/lib/public/DB/Types.php
+++ b/lib/public/DB/Types.php
@@ -110,4 +110,10 @@ final class Types {
* @since 21.0.0
*/
public const TIME = 'time';
+
+ /**
+ * @var string
+ * @since 24.0.0
+ */
+ public const JSON = 'json';
}