diff options
author | Vincent Petry <vincent@nextcloud.com> | 2022-06-10 17:07:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-10 17:07:38 +0200 |
commit | 2ee948e8d1a836696c514657c78804d1942f0d7b (patch) | |
tree | 1f2e2389dfa7ae94a946a89d37fccdc3b1d85152 | |
parent | 804ee11803a1fd7a5ac88793e77bd6b56a31bea0 (diff) | |
parent | bd8b2137e20a4d70bd643c32653c618ade685941 (diff) | |
download | nextcloud-server-2ee948e8d1a836696c514657c78804d1942f0d7b.tar.gz nextcloud-server-2ee948e8d1a836696c514657c78804d1942f0d7b.zip |
Merge pull request #30368 from nextcloud/dav-allow-object-properties
Allow DAV Object properties
-rw-r--r-- | apps/dav/appinfo/info.xml | 3 | ||||
-rw-r--r-- | apps/dav/composer/composer/autoload_classmap.php | 2 | ||||
-rw-r--r-- | apps/dav/composer/composer/autoload_static.php | 2 | ||||
-rw-r--r-- | apps/dav/lib/DAV/CustomPropertiesBackend.php | 70 | ||||
-rw-r--r-- | apps/dav/lib/Migration/RemoveObjectProperties.php | 65 | ||||
-rw-r--r-- | apps/dav/lib/Migration/Version1024Date20211221144219.php | 58 |
6 files changed, 187 insertions, 13 deletions
diff --git a/apps/dav/appinfo/info.xml b/apps/dav/appinfo/info.xml index 10f78d8332a..deb99b1c33b 100644 --- a/apps/dav/appinfo/info.xml +++ b/apps/dav/appinfo/info.xml @@ -5,7 +5,7 @@ <name>WebDAV</name> <summary>WebDAV endpoint</summary> <description>WebDAV endpoint</description> - <version>1.23.0</version> + <version>1.24.0</version> <licence>agpl</licence> <author>owncloud.org</author> <namespace>DAV</namespace> @@ -39,6 +39,7 @@ <step>OCA\DAV\Migration\RemoveOrphanEventsAndContacts</step> <step>OCA\DAV\Migration\RemoveClassifiedEventActivity</step> <step>OCA\DAV\Migration\RemoveDeletedUsersCalendarSubscriptions</step> + <step>OCA\DAV\Migration\RemoveObjectProperties</step> </post-migration> <live-migration> <step>OCA\DAV\Migration\ChunkCleanup</step> diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php index f40917fbd01..6f02140df40 100644 --- a/apps/dav/composer/composer/autoload_classmap.php +++ b/apps/dav/composer/composer/autoload_classmap.php @@ -257,6 +257,7 @@ return array( 'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => $baseDir . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php', 'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => $baseDir . '/../lib/Migration/RemoveClassifiedEventActivity.php', 'OCA\\DAV\\Migration\\RemoveDeletedUsersCalendarSubscriptions' => $baseDir . '/../lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php', + 'OCA\\DAV\\Migration\\RemoveObjectProperties' => $baseDir . '/../lib/Migration/RemoveObjectProperties.php', 'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => $baseDir . '/../lib/Migration/RemoveOrphanEventsAndContacts.php', 'OCA\\DAV\\Migration\\Version1004Date20170825134824' => $baseDir . '/../lib/Migration/Version1004Date20170825134824.php', 'OCA\\DAV\\Migration\\Version1004Date20170919104507' => $baseDir . '/../lib/Migration/Version1004Date20170919104507.php', @@ -278,6 +279,7 @@ return array( 'OCA\\DAV\\Migration\\Version1016Date20201109085907' => $baseDir . '/../lib/Migration/Version1016Date20201109085907.php', 'OCA\\DAV\\Migration\\Version1017Date20210216083742' => $baseDir . '/../lib/Migration/Version1017Date20210216083742.php', 'OCA\\DAV\\Migration\\Version1018Date20210312100735' => $baseDir . '/../lib/Migration/Version1018Date20210312100735.php', + 'OCA\\DAV\\Migration\\Version1024Date20211221144219' => $baseDir . '/../lib/Migration/Version1024Date20211221144219.php', 'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php', 'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php', 'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php', diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php index 60b437c9fac..296b8a497c9 100644 --- a/apps/dav/composer/composer/autoload_static.php +++ b/apps/dav/composer/composer/autoload_static.php @@ -272,6 +272,7 @@ class ComposerStaticInitDAV 'OCA\\DAV\\Migration\\RegisterBuildReminderIndexBackgroundJob' => __DIR__ . '/..' . '/../lib/Migration/RegisterBuildReminderIndexBackgroundJob.php', 'OCA\\DAV\\Migration\\RemoveClassifiedEventActivity' => __DIR__ . '/..' . '/../lib/Migration/RemoveClassifiedEventActivity.php', 'OCA\\DAV\\Migration\\RemoveDeletedUsersCalendarSubscriptions' => __DIR__ . '/..' . '/../lib/Migration/RemoveDeletedUsersCalendarSubscriptions.php', + 'OCA\\DAV\\Migration\\RemoveObjectProperties' => __DIR__ . '/..' . '/../lib/Migration/RemoveObjectProperties.php', 'OCA\\DAV\\Migration\\RemoveOrphanEventsAndContacts' => __DIR__ . '/..' . '/../lib/Migration/RemoveOrphanEventsAndContacts.php', 'OCA\\DAV\\Migration\\Version1004Date20170825134824' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170825134824.php', 'OCA\\DAV\\Migration\\Version1004Date20170919104507' => __DIR__ . '/..' . '/../lib/Migration/Version1004Date20170919104507.php', @@ -293,6 +294,7 @@ class ComposerStaticInitDAV 'OCA\\DAV\\Migration\\Version1016Date20201109085907' => __DIR__ . '/..' . '/../lib/Migration/Version1016Date20201109085907.php', 'OCA\\DAV\\Migration\\Version1017Date20210216083742' => __DIR__ . '/..' . '/../lib/Migration/Version1017Date20210216083742.php', 'OCA\\DAV\\Migration\\Version1018Date20210312100735' => __DIR__ . '/..' . '/../lib/Migration/Version1018Date20210312100735.php', + 'OCA\\DAV\\Migration\\Version1024Date20211221144219' => __DIR__ . '/..' . '/../lib/Migration/Version1024Date20211221144219.php', 'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php', 'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php', 'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php', diff --git a/apps/dav/lib/DAV/CustomPropertiesBackend.php b/apps/dav/lib/DAV/CustomPropertiesBackend.php index acee65cd00d..bd09ac2e4e6 100644 --- a/apps/dav/lib/DAV/CustomPropertiesBackend.php +++ b/apps/dav/lib/DAV/CustomPropertiesBackend.php @@ -31,6 +31,7 @@ use Sabre\DAV\PropertyStorage\Backend\BackendInterface; use Sabre\DAV\PropFind; use Sabre\DAV\PropPatch; use Sabre\DAV\Tree; +use Sabre\DAV\Xml\Property\Complex; use function array_intersect; class CustomPropertiesBackend implements BackendInterface { @@ -39,6 +40,21 @@ class CustomPropertiesBackend implements BackendInterface { private const TABLE_NAME = 'properties'; /** + * Value is stored as string. + */ + public const PROPERTY_TYPE_STRING = 1; + + /** + * Value is stored as XML fragment. + */ + public const PROPERTY_TYPE_XML = 2; + + /** + * Value is stored as a property object. + */ + public const PROPERTY_TYPE_OBJECT = 3; + + /** * Ignored properties * * @var string[] @@ -239,7 +255,7 @@ class CustomPropertiesBackend implements BackendInterface { $result = $qb->executeQuery(); $props = []; while ($row = $result->fetch()) { - $props[$row['propertyname']] = $row['propertyvalue']; + $props[$row['propertyname']] = $this->decodeValueFromDatabase($row['propertyvalue'], $row['valuetype']); } $result->closeCursor(); return $props; @@ -282,7 +298,7 @@ class CustomPropertiesBackend implements BackendInterface { $props = []; while ($row = $result->fetch()) { - $props[$row['propertyname']] = $row['propertyvalue']; + $props[$row['propertyname']] = $this->decodeValueFromDatabase($row['propertyvalue'], $row['valuetype']); } $result->closeCursor(); @@ -304,9 +320,9 @@ class CustomPropertiesBackend implements BackendInterface { ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; $insertStatement = 'INSERT INTO `*PREFIX*properties`' . - ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`) VALUES(?,?,?,?)'; + ' (`userid`,`propertypath`,`propertyname`,`propertyvalue`, `valuetype`) VALUES(?,?,?,?,?)'; - $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?' . + $updateStatement = 'UPDATE `*PREFIX*properties` SET `propertyvalue` = ?, `valuetype` = ?' . ' WHERE `userid` = ? AND `propertypath` = ? AND `propertyname` = ?'; // TODO: use "insert or update" strategy ? @@ -325,24 +341,22 @@ class CustomPropertiesBackend implements BackendInterface { ); } } else { - if ($propertyValue instanceOf \Sabre\DAV\Xml\Property\Complex) { - $propertyValue = $propertyValue->getXml(); - } elseif (!is_string($propertyValue)) { - $propertyValue = (string)$propertyValue; - } + [$value, $valueType] = $this->encodeValueForDatabase($propertyValue); if (!array_key_exists($propertyName, $existing)) { $this->connection->executeUpdate($insertStatement, [ $this->user->getUID(), $this->formatPath($path), $propertyName, - $propertyValue, + $value, + $valueType ] ); } else { $this->connection->executeUpdate($updateStatement, [ - $propertyValue, + $value, + $valueType, $this->user->getUID(), $this->formatPath($path), $propertyName, @@ -367,8 +381,40 @@ class CustomPropertiesBackend implements BackendInterface { private function formatPath(string $path): string { if (strlen($path) > 250) { return sha1($path); + } + + return $path; + } + + /** + * @param mixed $value + * @return array + */ + private function encodeValueForDatabase($value): array { + if (is_scalar($value)) { + $valueType = self::PROPERTY_TYPE_STRING; + } elseif ($value instanceof Complex) { + $valueType = self::PROPERTY_TYPE_XML; + $value = $value->getXml(); } else { - return $path; + $valueType = self::PROPERTY_TYPE_OBJECT; + $value = serialize($value); + } + return [$value, $valueType]; + } + + /** + * @return mixed|Complex|string + */ + private function decodeValueFromDatabase(string $value, int $valueType) { + switch ($valueType) { + case self::PROPERTY_TYPE_XML: + return new Complex($value); + case self::PROPERTY_TYPE_OBJECT: + return unserialize($value); + case self::PROPERTY_TYPE_STRING: + default: + return $value; } } } diff --git a/apps/dav/lib/Migration/RemoveObjectProperties.php b/apps/dav/lib/Migration/RemoveObjectProperties.php new file mode 100644 index 00000000000..c72dfbebfea --- /dev/null +++ b/apps/dav/lib/Migration/RemoveObjectProperties.php @@ -0,0 +1,65 @@ +<?php +/** + * @copyright Copyright (c) 2021, Thomas Citharel <nextcloud@tcit.fr>. + * + * @author Thomas Citharel <nextcloud@tcit.fr> + * + * @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 OCA\DAV\Migration; + +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\IRepairStep; + +class RemoveObjectProperties implements IRepairStep { + private const RESOURCE_TYPE_PROPERTY = '{DAV:}resourcetype'; + private const ME_CARD_PROPERTY = '{http://calendarserver.org/ns/}me-card'; + private const CALENDAR_TRANSP_PROPERTY = '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp'; + + /** @var IDBConnection */ + private $connection; + + /** + * RemoveObjectProperties constructor. + * + * @param IDBConnection $connection + */ + public function __construct(IDBConnection $connection) { + $this->connection = $connection; + } + + /** + * @inheritdoc + */ + public function getName() { + return 'Remove invalid object properties'; + } + + /** + * @inheritdoc + */ + public function run(IOutput $output) { + $query = $this->connection->getQueryBuilder(); + $updated = $query->delete('properties') + ->where($query->expr()->in('propertyname', $query->createNamedParameter([self::RESOURCE_TYPE_PROPERTY, self::ME_CARD_PROPERTY, self::CALENDAR_TRANSP_PROPERTY], IQueryBuilder::PARAM_STR_ARRAY))) + ->andWhere($query->expr()->eq('propertyvalue', $query->createNamedParameter('Object'))) + ->executeStatement(); + + $output->info("$updated invalid object properties removed."); + } +} diff --git a/apps/dav/lib/Migration/Version1024Date20211221144219.php b/apps/dav/lib/Migration/Version1024Date20211221144219.php new file mode 100644 index 00000000000..b93f8ac801e --- /dev/null +++ b/apps/dav/lib/Migration/Version1024Date20211221144219.php @@ -0,0 +1,58 @@ +<?php + +declare(strict_types=1); + +namespace OCA\DAV\Migration; + +use Closure; +use Doctrine\DBAL\Schema\SchemaException; +use OCA\DAV\DAV\CustomPropertiesBackend; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version1024Date20211221144219 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @throws SchemaException + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + $propertiesTable = $schema->getTable('properties'); + + if ($propertiesTable->hasColumn('valuetype')) { + return null; + } + $propertiesTable->addColumn('valuetype', Types::SMALLINT, [ + 'notnull' => false, + 'default' => CustomPropertiesBackend::PROPERTY_TYPE_STRING + ]); + + return $schema; + } + + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + */ + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } +} |