From e0ff151de890e49039732912d5ef8e4ff90fa5ee Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 1 Aug 2026 00:46:44 +0200 Subject: [PATCH 1/2] feat: keep a classname mapping instead of always storing the full name Signed-off-by: Robin Appelman --- .../composer/composer/autoload_classmap.php | 1 + .../composer/composer/autoload_static.php | 1 + .../Version1000Date20250929161325.php | 30 +++- .../Version1000Date20260731171922.php | 105 ++++++++++++ lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Server.php | 1 + lib/private/Sharing/ClassMapper.php | 161 ++++++++++++++++++ lib/private/Sharing/SharingBackend.php | 54 +++--- lib/private/Sharing/SharingManager.php | 13 +- tests/lib/Sharing/ClassMapperTest.php | 68 ++++++++ 11 files changed, 388 insertions(+), 48 deletions(-) create mode 100644 apps/sharing/lib/Migration/Version1000Date20260731171922.php create mode 100644 lib/private/Sharing/ClassMapper.php create mode 100644 tests/lib/Sharing/ClassMapperTest.php diff --git a/apps/sharing/composer/composer/autoload_classmap.php b/apps/sharing/composer/composer/autoload_classmap.php index 0d6e87b5cfd0d..103888349620f 100644 --- a/apps/sharing/composer/composer/autoload_classmap.php +++ b/apps/sharing/composer/composer/autoload_classmap.php @@ -26,5 +26,6 @@ 'OCA\\Sharing\\Controller\\ApiV1Controller' => $baseDir . '/../lib/Controller/ApiV1Controller.php', 'OCA\\Sharing\\Middleware\\ShareApiEnabledMiddleware' => $baseDir . '/../lib/Middleware/ShareApiEnabledMiddleware.php', 'OCA\\Sharing\\Migration\\Version1000Date20250929161325' => $baseDir . '/../lib/Migration/Version1000Date20250929161325.php', + 'OCA\\Sharing\\Migration\\Version1000Date20260731171922' => $baseDir . '/../lib/Migration/Version1000Date20260731171922.php', 'OCA\\Sharing\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php', ); diff --git a/apps/sharing/composer/composer/autoload_static.php b/apps/sharing/composer/composer/autoload_static.php index 22a3d83d9e4d0..f8dcfbd61f918 100644 --- a/apps/sharing/composer/composer/autoload_static.php +++ b/apps/sharing/composer/composer/autoload_static.php @@ -41,6 +41,7 @@ class ComposerStaticInitSharing 'OCA\\Sharing\\Controller\\ApiV1Controller' => __DIR__ . '/..' . '/../lib/Controller/ApiV1Controller.php', 'OCA\\Sharing\\Middleware\\ShareApiEnabledMiddleware' => __DIR__ . '/..' . '/../lib/Middleware/ShareApiEnabledMiddleware.php', 'OCA\\Sharing\\Migration\\Version1000Date20250929161325' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20250929161325.php', + 'OCA\\Sharing\\Migration\\Version1000Date20260731171922' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20260731171922.php', 'OCA\\Sharing\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php', ); diff --git a/apps/sharing/lib/Migration/Version1000Date20250929161325.php b/apps/sharing/lib/Migration/Version1000Date20250929161325.php index 1cea07e223102..9f59295a82db7 100644 --- a/apps/sharing/lib/Migration/Version1000Date20250929161325.php +++ b/apps/sharing/lib/Migration/Version1000Date20250929161325.php @@ -26,9 +26,17 @@ final class Version1000Date20250929161325 extends SimpleMigrationStep { public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { $schema = $schemaClosure(); - // TODO: Add mapping table for class names // TODO: Check indexes + $mappingTable = $schema->createTable('sharing_classmap'); + $mappingTable->addColumn('class_id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $mappingTable->addColumn('class_name', Types::STRING, ['length' => 64]); + $mappingTable->setPrimaryKey(['class_id']); + $mappingTable->addUniqueIndex(['class_name']); + $shareTable = $schema->createTable('sharing_share'); $shareTable->addColumn('id', Types::BIGINT); $shareTable->addColumn('owner_user_id', Types::STRING, ['length' => 64]); @@ -39,38 +47,42 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt $sourcesTable = $schema->createTable('sharing_share_sources'); $sourcesTable->addColumn('share_id', Types::BIGINT); - $sourcesTable->addColumn('source_class', Types::STRING, ['length' => 64]); + $sourcesTable->addColumn('source_class_id', Types::INTEGER); $sourcesTable->addColumn('source_value', Types::STRING, ['length' => 255]); - $sourcesTable->setPrimaryKey(['share_id', 'source_class', 'source_value']); + $sourcesTable->setPrimaryKey(['share_id', 'source_class_id', 'source_value']); $sourcesTable->addForeignKeyConstraint($shareTable->getName(), ['share_id'], ['id'], ['onDelete' => 'CASCADE']); + $sourcesTable->addForeignKeyConstraint($mappingTable->getName(), ['source_class_id'], ['class_id']); // TODO: Add possibility to mask permissions for recipients. For reshares the user may only mask permissions for their child recipients, not their self recipients $recipientsTable = $schema->createTable('sharing_share_recipients'); $recipientsTable->addColumn('share_id', Types::BIGINT); - $recipientsTable->addColumn('recipient_class', Types::STRING, ['length' => 64]); + $recipientsTable->addColumn('recipient_class_id', Types::INTEGER); $recipientsTable->addColumn('recipient_value', Types::STRING, ['length' => 255]); $recipientsTable->addColumn('recipient_instance', Types::STRING, ['length' => 128, 'notnull' => false]); $recipientsTable->addColumn('recipient_secret', Types::STRING, ['length' => 32]); $recipientsTable->addColumn('initiator_user_id', Types::STRING, ['length' => 64]); $recipientsTable->addColumn('initiator_instance', Types::STRING, ['length' => 128, 'notnull' => false]); - $recipientsTable->setPrimaryKey(['share_id', 'recipient_class', 'recipient_value']); + $recipientsTable->setPrimaryKey(['share_id', 'recipient_class_id', 'recipient_value']); $recipientsTable->addForeignKeyConstraint($shareTable->getName(), ['share_id'], ['id'], ['onDelete' => 'CASCADE']); // TODO: Maybe needs composite index with share_id $recipientsTable->addUniqueIndex(['recipient_secret']); + $recipientsTable->addForeignKeyConstraint($mappingTable->getName(), ['recipient_class_id'], ['class_id']); $propertiesTable = $schema->createTable('sharing_share_properties'); $propertiesTable->addColumn('share_id', Types::BIGINT); - $propertiesTable->addColumn('property_class', Types::STRING, ['length' => 64]); + $propertiesTable->addColumn('property_class_id', Types::INTEGER); $propertiesTable->addColumn('property_value', Types::STRING, ['length' => 1000, 'notnull' => false]); - $propertiesTable->setPrimaryKey(['share_id', 'property_class']); + $propertiesTable->setPrimaryKey(['share_id', 'property_class_id']); $propertiesTable->addForeignKeyConstraint($shareTable->getName(), ['share_id'], ['id'], ['onDelete' => 'CASCADE']); + $propertiesTable->addForeignKeyConstraint($mappingTable->getName(), ['property_class_id'], ['class_id']); $permissionsTable = $schema->createTable('sharing_share_permissions'); $permissionsTable->addColumn('share_id', Types::BIGINT); - $permissionsTable->addColumn('permission_class', Types::STRING, ['length' => 64]); + $permissionsTable->addColumn('permission_class_id', Types::INTEGER); $permissionsTable->addColumn('permission_enabled', Types::BOOLEAN); - $permissionsTable->setPrimaryKey(['share_id', 'permission_class']); + $permissionsTable->setPrimaryKey(['share_id', 'permission_class_id']); $permissionsTable->addForeignKeyConstraint($shareTable->getName(), ['share_id'], ['id'], ['onDelete' => 'CASCADE']); + $permissionsTable->addForeignKeyConstraint($mappingTable->getName(), ['permission_class_id'], ['class_id']); return $schema; } diff --git a/apps/sharing/lib/Migration/Version1000Date20260731171922.php b/apps/sharing/lib/Migration/Version1000Date20260731171922.php new file mode 100644 index 0000000000000..60eb95d586738 --- /dev/null +++ b/apps/sharing/lib/Migration/Version1000Date20260731171922.php @@ -0,0 +1,105 @@ +hasTable('sharing_classmap')) { + $table = $schema->createTable('sharing_classmap'); + $table->addColumn('class_id', Types::INTEGER, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('class_name', Types::STRING, ['length' => 64]); + $table->setPrimaryKey(['class_id']); + $table->addUniqueIndex(['class_name']); + } + + $sourcesTable = $schema->getTable('sharing_share_sources'); + if ($sourcesTable->hasColumn('source_class')) { + $sourcesTable->dropColumn('source_class'); + $sourcesTable->addColumn('source_class_id', Types::INTEGER); + $sourcesTable->dropPrimaryKey(); + $sourcesTable->setPrimaryKey(['share_id', 'source_class_id', 'source_value']); + $sourcesTable->addForeignKeyConstraint('sharing_classmap', ['source_class_id'], ['class_id']); + } + + $recipientsTable = $schema->getTable('sharing_share_recipients'); + if ($recipientsTable->hasColumn('recipient_class')) { + $recipientsTable->dropColumn('recipient_class'); + $recipientsTable->addColumn('recipient_class_id', Types::INTEGER); + $recipientsTable->dropPrimaryKey(); + $recipientsTable->setPrimaryKey(['share_id', 'recipient_class_id', 'recipient_value']); + $recipientsTable->addForeignKeyConstraint('sharing_classmap', ['recipient_class_id'], ['class_id']); + } + + $propertiesTable = $schema->getTable('sharing_share_properties'); + if ($propertiesTable->hasColumn('property_class')) { + $propertiesTable->dropColumn('property_class'); + $propertiesTable->addColumn('property_class_id', Types::INTEGER); + $propertiesTable->dropPrimaryKey(); + $propertiesTable->setPrimaryKey(['share_id', 'property_class_id']); + $propertiesTable->addForeignKeyConstraint('sharing_classmap', ['property_class_id'], ['class_id']); + } + + $permissionsTable = $schema->getTable('sharing_share_permissions'); + if ($permissionsTable->hasColumn('permission_class')) { + $permissionsTable->dropColumn('permission_class'); + $permissionsTable->addColumn('permission_class_id', Types::INTEGER); + $permissionsTable->dropPrimaryKey(); + $permissionsTable->setPrimaryKey(['share_id', 'permission_class_id']); + $permissionsTable->addForeignKeyConstraint('sharing_classmap', ['permission_class_id'], ['class_id']); + } + + return $schema; + } + + #[Override] + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + } +} diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 6472ccd5e2050..1c739ea8491fa 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -2306,6 +2306,7 @@ 'OC\\Share20\\UserDeletedListener' => $baseDir . '/lib/private/Share20/UserDeletedListener.php', 'OC\\Share20\\UserRemovedListener' => $baseDir . '/lib/private/Share20/UserRemovedListener.php', 'OC\\Share\\Constants' => $baseDir . '/lib/private/Share/Constants.php', + 'OC\\Sharing\\ClassMapper' => $baseDir . '/lib/private/Sharing/ClassMapper.php', 'OC\\Sharing\\ISharingLegacyBackend' => $baseDir . '/lib/private/Sharing/ISharingLegacyBackend.php', 'OC\\Sharing\\SharingBackend' => $baseDir . '/lib/private/Sharing/SharingBackend.php', 'OC\\Sharing\\SharingManager' => $baseDir . '/lib/private/Sharing/SharingManager.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index eb51034b2dff1..673febb840baa 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -2347,6 +2347,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OC\\Share20\\UserDeletedListener' => __DIR__ . '/../../..' . '/lib/private/Share20/UserDeletedListener.php', 'OC\\Share20\\UserRemovedListener' => __DIR__ . '/../../..' . '/lib/private/Share20/UserRemovedListener.php', 'OC\\Share\\Constants' => __DIR__ . '/../../..' . '/lib/private/Share/Constants.php', + 'OC\\Sharing\\ClassMapper' => __DIR__ . '/../../..' . '/lib/private/Sharing/ClassMapper.php', 'OC\\Sharing\\ISharingLegacyBackend' => __DIR__ . '/../../..' . '/lib/private/Sharing/ISharingLegacyBackend.php', 'OC\\Sharing\\SharingBackend' => __DIR__ . '/../../..' . '/lib/private/Sharing/SharingBackend.php', 'OC\\Sharing\\SharingManager' => __DIR__ . '/../../..' . '/lib/private/Sharing/SharingManager.php', diff --git a/lib/private/Server.php b/lib/private/Server.php index 7c1128a41690c..71d5b0b9fc0e0 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1156,6 +1156,7 @@ function () use ($c) { $this->registerAlias(\NCU\Sharing\ISharingRegistry::class, SharingRegistry::class); $this->registerAlias(\NCU\Sharing\ISharingManager::class, SharingManager::class); + $this->registerAlias(\NCU\Sharing\ISharingBackend::class, \OC\Sharing\SharingBackend::class); $this->connectDispatcher(); } diff --git a/lib/private/Sharing/ClassMapper.php b/lib/private/Sharing/ClassMapper.php new file mode 100644 index 0000000000000..75e3766bccbba --- /dev/null +++ b/lib/private/Sharing/ClassMapper.php @@ -0,0 +1,161 @@ + $map */ + private array $map = []; + + /** @var array */ + private array $reverseMap = []; + + private bool $loaded = false; + + public function __construct( + private readonly IDBConnection $connection, + ) { + } + + /** + * @param array{class_id: int|string, class_name: class-string} $row + */ + private function insertRow(array $row): void { + $id = (int)$row['class_id']; + $class = $row['class_name']; + $this->map[$id] = $class; + $this->reverseMap[$class] = $id; + } + + private function loadFromDb(): void { + if ($this->loaded) { + return; + } + + $query = $this->connection->getTypedQueryBuilder(); + $query->selectColumns('class_id', 'class_name') + ->from('sharing_classmap'); + $rows = $query->executeQuery()->fetchAll(); + + foreach ($rows as $row) { + /** @var array{class_id: int|string, class_name: class-string} $row */ + $this->insertRow($row); + } + + $this->loaded = true; + } + + /** + * @param class-string $className + */ + private function loadFromDbByName(string $className): ?int { + $query = $this->connection->getTypedQueryBuilder(); + $query->selectColumns('class_id', 'class_name') + ->from('sharing_classmap') + ->where($query->expr()->eq('class_name', $query->createNamedParameter($className))); + $row = $query->executeQuery()->fetchAssociative(); + + if ($row !== false) { + /** @var array{class_id: int|string, class_name: class-string} $row */ + $this->insertRow($row); + return (int)$row['class_id']; + } + + return null; + } + + /** + * @return class-string|null + */ + private function loadFromDbById(int $id): ?string { + $query = $this->connection->getTypedQueryBuilder(); + $query->selectColumns('class_id', 'class_name') + ->from('sharing_classmap') + ->where($query->expr()->eq('class_id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT))); + $row = $query->executeQuery()->fetchAssociative(); + + if ($row !== false) { + /** @var array{class_id: int|string, class_name: class-string} $row */ + $this->insertRow($row); + return $row['class_name']; + } + + return null; + } + + /** + * @param class-string $className + */ + private function insert(string $className): int { + $id = $this->loadFromDbByName($className); + if ($id !== null) { + return $id; + } + + $query = $this->connection->getTypedQueryBuilder(); + $query->insert('sharing_classmap') + ->values([ + 'class_name' => $query->createNamedParameter($className) + ]); + try { + $query->executeStatement(); + $id = $query->getLastInsertId(); + $this->map[$id] = $className; + $this->reverseMap[$className] = $id; + return $id; + } catch (Exception $exception) { + // handle concurrent inserts + if ($exception->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + $id = $this->loadFromDbByName($className); + if ($id === null) { + throw new \Exception(sprintf("Failed to insert '%s' into sharing_classmap, duplicate on insert but can't fetch it either", $className), $exception->getCode(), $exception); + } + + return $id; + } + + throw $exception; + } + } + + /** + * @param class-string $class + */ + public function getClassId(string $class): int { + $this->loadFromDb(); + + return $this->reverseMap[$class] ?? $this->insert($class); + } + + /** + * @return class-string + */ + public function getClassName(int $id): string { + $this->loadFromDb(); + if (isset($this->map[$id])) { + return $this->map[$id]; + } + + $class = $this->loadFromDbById($id); + if ($class) { + return $class; + } + + throw new \Exception(sprintf("Unknown mapped class '%d'", $id)); + } + + public function flush(): void { + $this->loaded = false; + $this->map = []; + $this->reverseMap = []; + } +} diff --git a/lib/private/Sharing/SharingBackend.php b/lib/private/Sharing/SharingBackend.php index 5d6cb5d4017d2..8e4716122a448 100644 --- a/lib/private/Sharing/SharingBackend.php +++ b/lib/private/Sharing/SharingBackend.php @@ -38,8 +38,6 @@ use OCP\L10N\IFactory; use RuntimeException; -// TODO: Add mapping table for class names in sources, recipients, permissions and properties - /** * @psalm-import-type SharingShare from Share */ @@ -53,6 +51,7 @@ public function __construct( private IAppConfig $appConfig, private ISharingRegistry $registry, private ISharingManager $manager, + private ClassMapper $classMapper, ) { $this->l10n = $factory->get('sharing'); } @@ -127,7 +126,7 @@ public function addShareSource(string $id, ShareSource $source): void { ->insert('sharing_share_sources') ->values([ 'share_id' => $qb->createNamedParameter($id), - 'source_class' => $qb->createNamedParameter($source->class), + 'source_class_id' => $qb->createNamedParameter($this->classMapper->getClassId($source->class), IQueryBuilder::PARAM_INT), 'source_value' => $qb->createNamedParameter($source->value), ]) ->executeStatement(); @@ -146,7 +145,7 @@ public function removeShareSource(string $id, ShareSource $source): void { $rowCount = $qb ->delete('sharing_share_sources') ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('source_class', $qb->createNamedParameter($source->class))) + ->andWhere($qb->expr()->eq('source_class_id', $qb->createNamedParameter($this->classMapper->getClassId($source->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('source_value', $qb->createNamedParameter($source->value))) ->executeStatement(); if ($rowCount === 0) { @@ -160,7 +159,7 @@ public function onSourceDeleted(ShareSource $source): array { $result = $qb ->selectDistinct('share_id') ->from('sharing_share_sources') - ->where($qb->expr()->eq('source_class', $qb->createNamedParameter($source->class))) + ->where($qb->expr()->eq('source_class_id', $qb->createNamedParameter($this->classMapper->getClassId($source->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('source_value', $qb->createNamedParameter($source->value))) ->executeQuery(); @@ -175,7 +174,7 @@ public function onSourceDeleted(ShareSource $source): array { $qb = $this->connection->getQueryBuilder(); $qb ->delete('sharing_share_sources') - ->where($qb->expr()->eq('source_class', $qb->createNamedParameter($source->class))) + ->where($qb->expr()->eq('source_class_id', $qb->createNamedParameter($this->classMapper->getClassId($source->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('source_value', $qb->createNamedParameter($source->value))) ->executeStatement(); @@ -197,7 +196,7 @@ public function addShareRecipient(string $id, ShareRecipient $recipient): void { $values = [ 'share_id' => $qb->createNamedParameter($id), - 'recipient_class' => $qb->createNamedParameter($recipient->class), + 'recipient_class_id' => $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT), 'recipient_value' => $qb->createNamedParameter($recipient->value), 'recipient_instance' => $qb->createNamedParameter($recipient->instance), 'recipient_secret' => $qb->createNamedParameter($recipient->secret), @@ -224,7 +223,7 @@ public function removeShareRecipient(string $id, ShareRecipient $recipient): voi $rowCount = $qb ->delete('sharing_share_recipients') ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('recipient_class', $qb->createNamedParameter($recipient->class))) + ->andWhere($qb->expr()->eq('recipient_class_id', $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('recipient_value', $qb->createNamedParameter($recipient->value))) ->andWhere( $recipient->instance === null @@ -243,7 +242,7 @@ public function onRecipientDeleted(ShareRecipient $recipient): array { $result = $qb ->selectDistinct('share_id') ->from('sharing_share_recipients') - ->where($qb->expr()->eq('recipient_class', $qb->createNamedParameter($recipient->class))) + ->where($qb->expr()->eq('recipient_class_id', $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('recipient_value', $qb->createNamedParameter($recipient->value))) ->andWhere( $recipient->instance === null @@ -263,7 +262,7 @@ public function onRecipientDeleted(ShareRecipient $recipient): array { $qb = $this->connection->getQueryBuilder(); $qb ->delete('sharing_share_recipients') - ->where($qb->expr()->eq('recipient_class', $qb->createNamedParameter($recipient->class))) + ->where($qb->expr()->eq('recipient_class_id', $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('recipient_value', $qb->createNamedParameter($recipient->value))) ->andWhere( $recipient->instance === null @@ -327,7 +326,7 @@ public function updateShareRecipientSecret(string $id, ShareRecipient $recipient ->update('sharing_share_recipients') ->set('recipient_secret', $qb->createNamedParameter($secret)) ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('recipient_class', $qb->createNamedParameter($recipient->class))) + ->andWhere($qb->expr()->eq('recipient_class_id', $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT))) ->andWhere($qb->expr()->eq('recipient_value', $qb->createNamedParameter($recipient->value))) ->andWhere( $recipient->instance === null @@ -356,7 +355,7 @@ public function createShareProperty(string $id, ShareProperty $property): void { ->insert('sharing_share_properties') ->values([ 'share_id' => $qb->createNamedParameter($id), - 'property_class' => $qb->createNamedParameter($property->class), + 'property_class_id' => $qb->createNamedParameter($this->classMapper->getClassId($property->class), IQueryBuilder::PARAM_INT), 'property_value' => $qb->createNamedParameter($value), ]) ->executeStatement(); @@ -381,7 +380,7 @@ public function updateShareProperty(string $id, ShareProperty $property): void { ->select('sp.property_value') ->from('sharing_share_properties', 'sp') ->where($qb->expr()->eq('sp.share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('sp.property_class', $qb->createNamedParameter($property->class))); + ->andWhere($qb->expr()->eq('sp.property_class_id', $qb->createNamedParameter($this->classMapper->getClassId($property->class), IQueryBuilder::PARAM_INT))); /** @var string|false $oldValue */ $oldValue = $qb->executeQuery()->fetchOne(); @@ -397,7 +396,7 @@ public function updateShareProperty(string $id, ShareProperty $property): void { ->update('sharing_share_properties') ->set('property_value', $qb->createNamedParameter($value)) ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('property_class', $qb->createNamedParameter($property->class))) + ->andWhere($qb->expr()->eq('property_class_id', $qb->createNamedParameter($this->classMapper->getClassId($property->class), IQueryBuilder::PARAM_INT))) ->executeStatement(); if ($rowCount === 0) { throw new ShareNotFoundException(); @@ -412,7 +411,7 @@ public function createSharePermission(string $id, SharePermission $permission): ->insert('sharing_share_permissions') ->values([ 'share_id' => $qb->createNamedParameter($id), - 'permission_class' => $qb->createNamedParameter($permission->class), + 'permission_class_id' => $qb->createNamedParameter($this->classMapper->getClassId($permission->class), IQueryBuilder::PARAM_INT), 'permission_enabled' => $qb->createNamedParameter($permission->enabled, IQueryBuilder::PARAM_BOOL), ]) ->executeStatement(); @@ -432,7 +431,7 @@ public function updateSharePermission(string $id, SharePermission $permission): ->update('sharing_share_permissions') ->set('permission_enabled', $qb->createNamedParameter($permission->enabled, IQueryBuilder::PARAM_BOOL)) ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->eq('permission_class', $qb->createNamedParameter($permission->class))) + ->andWhere($qb->expr()->eq('permission_class_id', $qb->createNamedParameter($this->classMapper->getClassId($permission->class), IQueryBuilder::PARAM_INT))) ->executeStatement(); if ($rowCount === 0) { throw new ShareNotFoundException(); @@ -450,13 +449,14 @@ public function selectSharePermissionPreset(string $id, string $permissionPreset $permissionPresetCompatiblePermissionTypeClasses = $this->registry->getPermissionPresetCompatiblePermissionTypeClasses()[$permissionPresetClass]; foreach (array_chunk($permissionPresetCompatiblePermissionTypeClasses, 1000) as $chunk) { + $chunkIds = array_map($this->classMapper->getClassId(...), $chunk); // Some permissions might not be compatible with the share, just ignore it and update the ones that are present. $qb = $this->connection->getQueryBuilder(); $qb ->update('sharing_share_permissions') ->set('permission_enabled', $qb->createNamedParameter(true, IQueryBuilder::PARAM_BOOL)) ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($id))) - ->andWhere($qb->expr()->in('permission_class', $qb->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))) + ->andWhere($qb->expr()->in('permission_class_id', $qb->createNamedParameter($chunkIds, IQueryBuilder::PARAM_INT_ARRAY))) ->executeStatement(); } @@ -590,7 +590,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, foreach ($recipientTypeValues as $recipientTypeClass => $recipientValues) { $qb->orWhere($qb->expr()->andX( - $qb->expr()->eq('sr.recipient_class', $qb->createNamedParameter($recipientTypeClass)), + $qb->expr()->eq('sr.recipient_class_id', $qb->createNamedParameter($this->classMapper->getClassId($recipientTypeClass), IQueryBuilder::PARAM_INT)), // TODO: Add chunking $qb->expr()->in('sr.recipient_value', $qb->createNamedParameter($recipientValues, IQueryBuilder::PARAM_STR_ARRAY)), $qb->expr()->isNull('sr.recipient_instance'), @@ -634,7 +634,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, if ($filterSourceTypeClass !== null) { $sourceTypeFilters = [ $qb->expr()->eq('s.id', 'ss.share_id'), - $qb->expr()->eq('ss.source_class', $qb->createNamedParameter($filterSourceTypeClass)), + $qb->expr()->eq('ss.source_class_id', $qb->createNamedParameter($this->classMapper->getClassId($filterSourceTypeClass), IQueryBuilder::PARAM_INT)), ]; if ($filterSourceTypeValue !== null) { @@ -704,7 +704,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $qb ->select( 'ss.share_id', - 'ss.source_class', + 'ss.source_class_id', 'ss.source_value', ) ->from('sharing_share_sources', 'ss') @@ -713,7 +713,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $result = $qb->executeQuery(); foreach ($result->fetchAll() as $row) { /** @var class-string $typeClass */ - $typeClass = $row['source_class']; + $typeClass = $this->classMapper->getClassName((int)$row['source_class_id']); if (!isset($registrySourceTypes[$typeClass])) { // Skip sources that are currently not compatible, but don't remove them. continue; @@ -741,7 +741,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $qb ->select( 'sr.share_id', - 'sr.recipient_class', + 'sr.recipient_class_id', 'sr.recipient_value', 'sr.recipient_instance', 'sr.recipient_secret', @@ -753,7 +753,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, foreach ($qb->executeQuery()->fetchAll() as $row) { /** @var class-string $typeClass */ - $typeClass = $row['recipient_class']; + $typeClass = $this->classMapper->getClassName((int)$row['recipient_class_id']); if (!isset($registryRecipientTypes[$typeClass])) { // Skip recipients that are currently not compatible, but don't remove them. continue; @@ -858,7 +858,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $qb ->select( 'sp.share_id', - 'sp.property_class', + 'sp.property_class_id', 'sp.property_value', ) ->from('sharing_share_properties', 'sp') @@ -873,7 +873,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, } /** @var class-string $propertyTypeClass */ - $propertyTypeClass = $row['property_class']; + $propertyTypeClass = $this->classMapper->getClassName((int)$row['property_class_id']); if (!isset($registryPropertyTypeCompatibleSourceTypeClasses[$propertyTypeClass], $registryPropertyTypeCompatibleRecipientTypeClasses[$propertyTypeClass])) { // Skip properties that are currently not compatible, but don't remove them. continue; @@ -928,7 +928,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $qb ->select( 'sp.share_id', - 'sp.permission_class', + 'sp.permission_class_id', 'sp.permission_enabled', ) ->from('sharing_share_permissions', 'sp') @@ -940,7 +940,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, $id = (string)$row['share_id']; /** @var class-string $permissionTypeClass */ - $permissionTypeClass = $row['permission_class']; + $permissionTypeClass = $this->classMapper->getClassName((int)$row['permission_class_id']); if (!isset($shareCompatiblePermissionTypeClasses[$id][$permissionTypeClass])) { // Skip permissions that are currently not compatible, but don't remove them. continue; diff --git a/lib/private/Sharing/SharingManager.php b/lib/private/Sharing/SharingManager.php index dc96ad31a85ff..e8246f08a6c3d 100644 --- a/lib/private/Sharing/SharingManager.php +++ b/lib/private/Sharing/SharingManager.php @@ -31,7 +31,6 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventDispatcher; use OCP\EventDispatcher\IEventListener; -use OCP\IAppConfig; use OCP\IDBConnection; use OCP\IL10N; use OCP\Interaction\Actions\ShareAction; @@ -60,8 +59,6 @@ private IL10N $l10n; - private ISharingBackend $backend; - public function __construct( IEventDispatcher $eventDispatcher, private IUserManager $userManager, @@ -69,18 +66,10 @@ public function __construct( private ISnowflakeGenerator $snowflakeGenerator, private IDBConnection $dbConnection, private ISharingRegistry $registry, - IAppConfig $appConfig, + private ISharingBackend $backend, ) { $this->randomizer = new Randomizer(); $this->l10n = $l10nFactory->get('sharing'); - $this->backend = new SharingBackend( - $l10nFactory, - $dbConnection, - $userManager, - $appConfig, - $registry, - $this, - ); $eventDispatcher->addServiceListener(BeforeUserDeletedEvent::class, self::class); } diff --git a/tests/lib/Sharing/ClassMapperTest.php b/tests/lib/Sharing/ClassMapperTest.php new file mode 100644 index 0000000000000..04ba24756e675 --- /dev/null +++ b/tests/lib/Sharing/ClassMapperTest.php @@ -0,0 +1,68 @@ +connection = Server::get(IDBConnection::class); + $this->clearMappings(); + $this->classMapper = $this->getMapper(); + } + + private function clearMappings(): void { + $query = $this->connection->getTypedQueryBuilder(); + $cleanupClasses = [IDBConnection::class, ClassMapper::class]; + $query->delete('sharing_classmap') + ->where($query->expr()->in('class_name', $query->createNamedParameter($cleanupClasses, IQueryBuilder::PARAM_STR_ARRAY))); + $query->executeStatement(); + } + + private function getMapper(): ClassMapper { + return new ClassMapper($this->connection); + } + + public function testGetInsert(): void { + $id = $this->classMapper->getClassId(IDBConnection::class); + $this->assertEquals($id, $this->classMapper->getClassId(IDBConnection::class)); + $this->assertEquals(IDBConnection::class, $this->classMapper->getClassName($id)); + + $this->assertEquals($id, $this->getMapper()->getClassId(IDBConnection::class)); + } + + public function testInsertConcurrent(): void { + $concurrentMapper = $this->getMapper(); + + // trigger a load + $this->classMapper->getClassId(ClassMapper::class); + + $id = $concurrentMapper->getClassId(IDBConnection::class); + $this->assertEquals($id, $this->classMapper->getClassId(IDBConnection::class)); + $this->assertEquals(IDBConnection::class, $this->classMapper->getClassName($id)); + } + + public function testGetUnknownId(): void { + $this->expectException(\Exception::class); + $this->classMapper->getClassName(PHP_INT_MAX - 1); + } +} From 2e21b7fbc9b7578bef58d08d866c7041b4624020 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Wed, 5 Aug 2026 19:49:27 +0200 Subject: [PATCH 2/2] fix: use an event to handle sharing backends setting default values on existing shares Signed-off-by: Robin Appelman --- lib/composer/composer/autoload_classmap.php | 1 + lib/composer/composer/autoload_static.php | 1 + lib/private/Sharing/SharingBackend.php | 97 ++++++++++++++++++- lib/private/Sharing/SharingManager.php | 95 ++++-------------- .../Sharing/Event/SharesDefaultSetEvent.php | 46 +++++++++ lib/unstable/Sharing/ISharingManager.php | 16 --- 6 files changed, 157 insertions(+), 99 deletions(-) create mode 100644 lib/unstable/Sharing/Event/SharesDefaultSetEvent.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 1c739ea8491fa..cee1ff2d0fc61 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -37,6 +37,7 @@ 'NCU\\Security\\Signature\\ISignatureManager' => $baseDir . '/lib/unstable/Security/Signature/ISignatureManager.php', 'NCU\\Security\\Signature\\ISignedRequest' => $baseDir . '/lib/unstable/Security/Signature/ISignedRequest.php', 'NCU\\Security\\Signature\\Model\\Signatory' => $baseDir . '/lib/unstable/Security/Signature/Model/Signatory.php', + 'NCU\\Sharing\\Event\\SharesDefaultSetEvent' => $baseDir . '/lib/unstable/Sharing/Event/SharesDefaultSetEvent.php', 'NCU\\Sharing\\Exception\\AShareException' => $baseDir . '/lib/unstable/Sharing/Exception/AShareException.php', 'NCU\\Sharing\\Exception\\ShareInvalidException' => $baseDir . '/lib/unstable/Sharing/Exception/ShareInvalidException.php', 'NCU\\Sharing\\Exception\\ShareNotFoundException' => $baseDir . '/lib/unstable/Sharing/Exception/ShareNotFoundException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 673febb840baa..63487a01bb964 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -78,6 +78,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'NCU\\Security\\Signature\\ISignatureManager' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignatureManager.php', 'NCU\\Security\\Signature\\ISignedRequest' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/ISignedRequest.php', 'NCU\\Security\\Signature\\Model\\Signatory' => __DIR__ . '/../../..' . '/lib/unstable/Security/Signature/Model/Signatory.php', + 'NCU\\Sharing\\Event\\SharesDefaultSetEvent' => __DIR__ . '/../../..' . '/lib/unstable/Sharing/Event/SharesDefaultSetEvent.php', 'NCU\\Sharing\\Exception\\AShareException' => __DIR__ . '/../../..' . '/lib/unstable/Sharing/Exception/AShareException.php', 'NCU\\Sharing\\Exception\\ShareInvalidException' => __DIR__ . '/../../..' . '/lib/unstable/Sharing/Exception/ShareInvalidException.php', 'NCU\\Sharing\\Exception\\ShareNotFoundException' => __DIR__ . '/../../..' . '/lib/unstable/Sharing/Exception/ShareNotFoundException.php', diff --git a/lib/private/Sharing/SharingBackend.php b/lib/private/Sharing/SharingBackend.php index 8e4716122a448..1cb86c35ba68b 100644 --- a/lib/private/Sharing/SharingBackend.php +++ b/lib/private/Sharing/SharingBackend.php @@ -10,10 +10,10 @@ namespace OC\Sharing; use Exception; +use NCU\Sharing\Event\SharesDefaultSetEvent; use NCU\Sharing\Exception\ShareInvalidException; use NCU\Sharing\Exception\ShareNotFoundException; use NCU\Sharing\ISharingBackend; -use NCU\Sharing\ISharingManager; use NCU\Sharing\ISharingRegistry; use NCU\Sharing\Permission\ISharePermissionType; use NCU\Sharing\Permission\SharePermission; @@ -30,6 +30,7 @@ use NCU\Sharing\Source\IShareSourceType; use NCU\Sharing\Source\ShareSource; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\EventDispatcher\IEventDispatcher; use OCP\IAppConfig; use OCP\IDBConnection; use OCP\IL10N; @@ -50,7 +51,7 @@ public function __construct( private IUserManager $userManager, private IAppConfig $appConfig, private ISharingRegistry $registry, - private ISharingManager $manager, + private IEventDispatcher $eventDispatcher, private ClassMapper $classMapper, ) { $this->l10n = $factory->get('sharing'); @@ -981,6 +982,7 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, } } + $defaultSet = false; foreach (array_keys($shares) as $id) { foreach (array_keys($registryPropertyTypes) as $propertyTypeClass) { $share = $shares[$id]; @@ -989,7 +991,8 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, && isset($shareSourceTypeClasses[$id], $shareRecipientTypeClasses[$id]) && array_intersect($registryPropertyTypeCompatibleSourceTypeClasses[$propertyTypeClass], array_keys($shareSourceTypeClasses[$id])) !== [] && array_intersect($registryPropertyTypeCompatibleRecipientTypeClasses[$propertyTypeClass], array_keys($shareRecipientTypeClasses[$id])) !== []) { - $shares[$id] = $this->manager->createSharePropertyDefaultValue($shares[$id], $propertyTypeClass); + $shares[$id] = $this->createSharePropertyDefaultValue($shares[$id], $propertyTypeClass); + $defaultSet = true; } } } @@ -998,11 +1001,95 @@ private function list(ShareAccessContext $accessContext, ?string $filterShareID, foreach (array_keys($shareCompatiblePermissionTypeClasses[$id]) as $permissionTypeClass) { $share = $shares[$id]; if (!isset($share->permissions[$permissionTypeClass])) { - $shares[$id] = $this->manager->createSharePermissionDefaultValue($shares[$id], $permissionTypeClass); + $shares[$id] = $this->createSharePermissionDefaultValue($shares[$id], $permissionTypeClass); + $defaultSet = true; } } } - return array_values($shares); + $shares = array_values($shares); + if ($defaultSet && $shares !== []) { + $event = new SharesDefaultSetEvent($shares); + $this->eventDispatcher->dispatchTyped($event); + $shares = $event->getShares(); + } + + return $shares; + } + + /** + * @return non-negative-int + */ + public function generateTimestamp(): int { + $time = (int)(microtime(true) * 1000.0); + if ($time < 0) { + throw new RuntimeException('Have you invented time travel?'); + } + + return $time; + } + + /** + * @param class-string $propertyTypeClass + */ + public function createSharePropertyDefaultValue(Share $share, string $propertyTypeClass): Share { + $timestamp = $this->generateTimestamp(); + $this->setLastUpdated([$share->id], $timestamp); + + if (($propertyType = $this->registry->getPropertyTypes()[$propertyTypeClass] ?? null) === null) { + throw new RuntimeException('The property is not registered: ' . $propertyTypeClass); + } + + $property = new ShareProperty($propertyTypeClass, $propertyType->getDefaultValue($share)); + + $this->createShareProperty($share->id, $property); + + $properties = $share->properties; + $properties[$propertyTypeClass] = $property; + + $share = new Share( + $share->id, + $share->owner, + $timestamp, + $share->state, + $share->sources, + $share->recipients, + $properties, + $share->permissions, + ); + + return $share; + } + + /** + * @param class-string $permissionTypeClass + */ + public function createSharePermissionDefaultValue(Share $share, string $permissionTypeClass): Share { + $timestamp = $this->generateTimestamp(); + $this->setLastUpdated([$share->id], $timestamp); + + if (($permissionType = $this->registry->getPermissionTypes()[$permissionTypeClass] ?? null) === null) { + throw new RuntimeException('The permission is not registered: ' . $permissionTypeClass); + } + + $permission = new SharePermission($permissionTypeClass, $permissionType->isEnabledByDefault()); + + $this->createSharePermission($share->id, $permission); + + $permissions = $share->permissions; + $permissions[$permissionTypeClass] = $permission; + + $share = new Share( + $share->id, + $share->owner, + $timestamp, + $share->state, + $share->sources, + $share->recipients, + $share->properties, + $permissions, + ); + + return $share; } } diff --git a/lib/private/Sharing/SharingManager.php b/lib/private/Sharing/SharingManager.php index e8246f08a6c3d..8ec261906ce0a 100644 --- a/lib/private/Sharing/SharingManager.php +++ b/lib/private/Sharing/SharingManager.php @@ -10,6 +10,7 @@ namespace OC\Sharing; use Exception; +use NCU\Sharing\Event\SharesDefaultSetEvent; use NCU\Sharing\Exception\ShareInvalidException; use NCU\Sharing\Exception\ShareOperationForbiddenException; use NCU\Sharing\ISharingBackend; @@ -52,7 +53,7 @@ /** * @psalm-import-type SharingShare from Share - * @template-implements IEventListener + * @template-implements IEventListener */ final readonly class SharingManager implements ISharingManager, IEventListener { private Randomizer $randomizer; @@ -429,40 +430,6 @@ public function updateShareRecipientSecret(ShareAccessContext $accessContext, st $this->processShareUpdates([$id]); } - #[\Override] - public function createSharePropertyDefaultValue(Share $share, string $propertyTypeClass): Share { - $this->assertInTransaction(); - - $timestamp = $this->generateTimestamp(); - $this->backend->setLastUpdated([$share->id], $timestamp); - - if (($propertyType = $this->registry->getPropertyTypes()[$propertyTypeClass] ?? null) === null) { - throw new RuntimeException('The property is not registered: ' . $propertyTypeClass); - } - - $property = new ShareProperty($propertyTypeClass, $propertyType->getDefaultValue($share)); - - $this->backend->createShareProperty($share->id, $property); - - $properties = $share->properties; - $properties[$propertyTypeClass] = $property; - - $share = new Share( - $share->id, - $share->owner, - $timestamp, - $share->state, - $share->sources, - $share->recipients, - $properties, - $share->permissions, - ); - - [$share] = $this->processShareUpdates([$share]); - - return $share; - } - #[\Override] public function updateShareProperty(ShareAccessContext $accessContext, string $id, ShareProperty $property): void { $this->assertInTransaction(); @@ -488,40 +455,6 @@ public function updateShareProperty(ShareAccessContext $accessContext, string $i $this->processShareUpdates([$id]); } - #[\Override] - public function createSharePermissionDefaultValue(Share $share, string $permissionTypeClass): Share { - $this->assertInTransaction(); - - $timestamp = $this->generateTimestamp(); - $this->backend->setLastUpdated([$share->id], $timestamp); - - if (($permissionType = $this->registry->getPermissionTypes()[$permissionTypeClass] ?? null) === null) { - throw new RuntimeException('The permission is not registered: ' . $permissionTypeClass); - } - - $permission = new SharePermission($permissionTypeClass, $permissionType->isEnabledByDefault()); - - $this->backend->createSharePermission($share->id, $permission); - - $permissions = $share->permissions; - $permissions[$permissionTypeClass] = $permission; - - $share = new Share( - $share->id, - $share->owner, - $timestamp, - $share->state, - $share->sources, - $share->recipients, - $share->properties, - $permissions, - ); - - [$share] = $this->processShareUpdates([$share]); - - return $share; - } - #[\Override] public function updateSharePermission(ShareAccessContext $accessContext, string $id, SharePermission $permission): void { $this->assertInTransaction(); @@ -611,16 +544,22 @@ public function getShares(ShareAccessContext $accessContext, ?string $filterSour #[\Override] public function handle(Event $event): void { - $shareUser = new ShareUser($event->getUser()->getUID(), null); + if ($event instanceof SharesDefaultSetEvent) { + $this->processShareUpdates($event->getShares()); + } - try { - $this->dbConnection->beginTransaction(); - $this->onOwnerDeleted(new ShareAccessContext(overrideChecks: true), $shareUser); - $this->onInitiatorDeleted(new ShareAccessContext(overrideChecks: true), $shareUser); - $this->dbConnection->commit(); - } catch (Exception $exception) { - $this->dbConnection->rollBack(); - throw $exception; + if ($event instanceof BeforeUserDeletedEvent) { + $shareUser = new ShareUser($event->getUser()->getUID(), null); + + try { + $this->dbConnection->beginTransaction(); + $this->onOwnerDeleted(new ShareAccessContext(overrideChecks: true), $shareUser); + $this->onInitiatorDeleted(new ShareAccessContext(overrideChecks: true), $shareUser); + $this->dbConnection->commit(); + } catch (Exception $exception) { + $this->dbConnection->rollBack(); + throw $exception; + } } } diff --git a/lib/unstable/Sharing/Event/SharesDefaultSetEvent.php b/lib/unstable/Sharing/Event/SharesDefaultSetEvent.php new file mode 100644 index 0000000000000..c36f9526b3149 --- /dev/null +++ b/lib/unstable/Sharing/Event/SharesDefaultSetEvent.php @@ -0,0 +1,46 @@ + $shares + * @experimental 35.0.0 + */ + public function __construct( + private array $shares, + ) { + parent::__construct(); + } + + /** + * @return non-empty-list + * @experimental 35.0.0 + */ + public function getShares(): array { + return $this->shares; + } + + /** + * @param non-empty-list $shares + * @experimental 35.0.0 + */ + public function setShares(array $shares): void { + $this->shares = $shares; + } +} diff --git a/lib/unstable/Sharing/ISharingManager.php b/lib/unstable/Sharing/ISharingManager.php index 21128680aaefc..ebbe7b6059c4f 100644 --- a/lib/unstable/Sharing/ISharingManager.php +++ b/lib/unstable/Sharing/ISharingManager.php @@ -13,9 +13,7 @@ use NCU\Sharing\Exception\ShareNotFoundException; use NCU\Sharing\Exception\ShareOperationForbiddenException; use NCU\Sharing\Permission\ISharePermissionPreset; -use NCU\Sharing\Permission\ISharePermissionType; use NCU\Sharing\Permission\SharePermission; -use NCU\Sharing\Property\ISharePropertyType; use NCU\Sharing\Property\ShareProperty; use NCU\Sharing\Recipient\IShareRecipientType; use NCU\Sharing\Recipient\ShareRecipient; @@ -150,13 +148,6 @@ public function onInitiatorDeleted(ShareAccessContext $accessContext, ShareUser */ public function updateShareRecipientSecret(ShareAccessContext $accessContext, string $id, ShareRecipient $recipient, string $secret): void; - /** - * @param class-string $propertyTypeClass - * @throws ShareNotFoundException - * @experimental 35.0.0 - */ - public function createSharePropertyDefaultValue(Share $share, string $propertyTypeClass): Share; - /** * Update a property of a share. * @@ -167,13 +158,6 @@ public function createSharePropertyDefaultValue(Share $share, string $propertyTy */ public function updateShareProperty(ShareAccessContext $accessContext, string $id, ShareProperty $property): void; - /** - * @param class-string $permissionTypeClass - * @throws ShareNotFoundException - * @experimental 35.0.0 - */ - public function createSharePermissionDefaultValue(Share $share, string $permissionTypeClass): Share; - /** * Update a permission of a share. *