Skip to content

Commit 3e9f34e

Browse files
committed
feat(Sharing): Add internal recipient IDs
Signed-off-by: provokateurin <kate@provokateurin.de>
1 parent 5567e14 commit 3e9f34e

6 files changed

Lines changed: 76 additions & 27 deletions

File tree

apps/sharing/appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<name>Sharing</name>
1010
<summary>TODO</summary>
1111
<description>TODO</description>
12-
<version>2.0.0-dev.1</version>
12+
<version>2.0.0-dev.2</version>
1313
<licence>AGPL-3.0-or-later</licence>
1414
<author>Kate Döen</author>
1515
<namespace>Sharing</namespace>

apps/sharing/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@
2929
'OCA\\Sharing\\Migration\\Version1000Date20250929161325' => $baseDir . '/../lib/Migration/Version1000Date20250929161325.php',
3030
'OCA\\Sharing\\Migration\\Version1000Date20260731171922' => $baseDir . '/../lib/Migration/Version1000Date20260731171922.php',
3131
'OCA\\Sharing\\Migration\\Version1000Date20260826073021' => $baseDir . '/../lib/Migration/Version1000Date20260826073021.php',
32+
'OCA\\Sharing\\Migration\\Version1000Date20260826115938' => $baseDir . '/../lib/Migration/Version1000Date20260826115938.php',
3233
'OCA\\Sharing\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
3334
);

apps/sharing/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ComposerStaticInitSharing
4444
'OCA\\Sharing\\Migration\\Version1000Date20250929161325' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20250929161325.php',
4545
'OCA\\Sharing\\Migration\\Version1000Date20260731171922' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20260731171922.php',
4646
'OCA\\Sharing\\Migration\\Version1000Date20260826073021' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20260826073021.php',
47+
'OCA\\Sharing\\Migration\\Version1000Date20260826115938' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20260826115938.php',
4748
'OCA\\Sharing\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
4849
);
4950

apps/sharing/lib/Migration/Version1000Date20250929161325.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,16 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
5555

5656
// TODO: Add possibility to mask permissions for recipients. For reshares the user may only mask permissions for their child recipients, not their self recipients
5757
$recipientsTable = $schema->createTable('sharing_share_recipients');
58+
$recipientsTable->addColumn('id', Types::BIGINT);
5859
$recipientsTable->addColumn('share_id', Types::BIGINT);
5960
$recipientsTable->addColumn('recipient_class_id', Types::INTEGER);
6061
$recipientsTable->addColumn('recipient_value', Types::STRING, ['length' => 255]);
6162
$recipientsTable->addColumn('recipient_instance', Types::STRING, ['length' => 128, 'notnull' => false]);
6263
$recipientsTable->addColumn('recipient_secret', Types::STRING, ['length' => 32]);
6364
$recipientsTable->addColumn('initiator_user_id', Types::STRING, ['length' => 64]);
6465
$recipientsTable->addColumn('initiator_instance', Types::STRING, ['length' => 128, 'notnull' => false]);
65-
$recipientsTable->setPrimaryKey(['share_id', 'recipient_class_id', 'recipient_value']);
66+
$recipientsTable->setPrimaryKey(['id']);
67+
$recipientsTable->addUniqueIndex(['share_id', 'recipient_class_id', 'recipient_value']);
6668
$recipientsTable->addForeignKeyConstraint($shareTable->getName(), ['share_id'], ['id'], ['onDelete' => 'CASCADE']);
6769
// TODO: Maybe needs composite index with share_id
6870
$recipientsTable->addUniqueIndex(['recipient_secret']);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\Sharing\Migration;
11+
12+
use Closure;
13+
use Doctrine\DBAL\Schema\SchemaException;
14+
use OCP\DB\ISchemaWrapper;
15+
use OCP\DB\Types;
16+
use OCP\Migration\IOutput;
17+
use OCP\Migration\SimpleMigrationStep;
18+
use Override;
19+
20+
final class Version1000Date20260826115938 extends SimpleMigrationStep {
21+
/**
22+
* @param Closure():ISchemaWrapper $schemaClosure
23+
* @throws SchemaException
24+
*/
25+
#[Override]
26+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
27+
$schema = $schemaClosure();
28+
29+
$recipientsTable = $schema->getTable('sharing_share_recipients');
30+
if (!$recipientsTable->hasColumn('id')) {
31+
$recipientsTable->addColumn('id', Types::BIGINT);
32+
$recipientsTable->dropPrimaryKey();
33+
$recipientsTable->setPrimaryKey(['id']);
34+
$recipientsTable->addUniqueIndex(['share_id', 'recipient_class_id', 'recipient_value']);
35+
}
36+
37+
return $schema;
38+
}
39+
}

lib/private/Sharing/SharingBackend.php

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
use OCP\IUser;
4040
use OCP\IUserManager;
4141
use OCP\L10N\IFactory;
42+
use OCP\Snowflake\ISnowflakeGenerator;
4243
use Psr\Clock\ClockInterface;
4344
use RuntimeException;
4445

@@ -57,6 +58,7 @@ public function __construct(
5758
private IEventDispatcher $eventDispatcher,
5859
private ClassMapper $classMapper,
5960
private ClockInterface $clock,
61+
private ISnowflakeGenerator $snowflakeGenerator,
6062
) {
6163
$this->l10n = $factory->get('sharing');
6264
}
@@ -225,6 +227,7 @@ public function addShareRecipient(string $id, ShareRecipient $recipient): void {
225227
$qb = $this->connection->getQueryBuilder();
226228

227229
$values = [
230+
'id' => $qb->createNamedParameter($this->snowflakeGenerator->nextId()),
228231
'share_id' => $qb->createNamedParameter($id),
229232
'recipient_class_id' => $qb->createNamedParameter($this->classMapper->getClassId($recipient->class), IQueryBuilder::PARAM_INT),
230233
'recipient_value' => $qb->createNamedParameter($recipient->value),
@@ -671,7 +674,7 @@ private function list(
671674
}
672675

673676
// The key type is array-key, because PHP will automatically cast the value. We can't type it as integer though, because we need to also support 32 bit systems and there the autocasting doesn't happen, if the value is too large.
674-
/** @var array<array-key, array{id: non-empty-string, owner: ShareUser, last_updated: numeric-string, state: ShareState, user_status: ShareUserStatus, sources: list<ShareSource>, recipients: list<ShareRecipient>, properties: array<class-string<ISharePropertyType>, ShareProperty>, permissions: array<class-string<ISharePermissionType>, SharePermission>}> $shares */
677+
/** @var array<array-key, array{id: non-empty-string, owner: ShareUser, last_updated: numeric-string, state: ShareState, user_status: ShareUserStatus, sources: list<ShareSource>, recipients: array<array-key, ShareRecipient>, properties: array<class-string<ISharePropertyType>, ShareProperty>, permissions: array<class-string<ISharePermissionType>, SharePermission>}> $shares */
675678
$shares = [];
676679
foreach ($queries as $qb) {
677680
$qb
@@ -731,14 +734,14 @@ private function list(
731734
continue;
732735
}
733736

734-
/** @var non-empty-string $id */
735-
$id = (string)$row['id'];
737+
/** @var non-empty-string $shareId */
738+
$shareId = (string)$row['id'];
736739
/** @var numeric-string $lastUpdated */
737740
$lastUpdated = (string)$row['last_updated'];
738741
/** @var string $state */
739742
$state = $row['state'];
740-
$shares[$id] ??= [
741-
'id' => $id,
743+
$shares[$shareId] ??= [
744+
'id' => $shareId,
742745
'owner' => new ShareUser($ownerUserId, $ownerInstance),
743746
'last_updated' => $lastUpdated,
744747
'state' => ShareState::from($state),
@@ -850,15 +853,15 @@ private function list(
850853
}
851854

852855
$value = $row['source_value'];
853-
$id = $row['share_id'];
854-
$shares[$id]['sources'][] = new ShareSource(
856+
$shareId = $row['share_id'];
857+
$shares[$shareId]['sources'][] = new ShareSource(
855858
$typeClass,
856859
$value,
857860
$shareSourceMetas[$typeClass][$value] ?? null,
858861
);
859862

860-
$shareSourceTypeClasses[$id] ??= [];
861-
$shareSourceTypeClasses[$id][$typeClass] = true;
863+
$shareSourceTypeClasses[$shareId] ??= [];
864+
$shareSourceTypeClasses[$shareId][$typeClass] = true;
862865
}
863866
}
864867

@@ -869,6 +872,7 @@ private function list(
869872
$qb = $this->connection->getQueryBuilder();
870873
$qb
871874
->select(
875+
'sr.id',
872876
'sr.share_id',
873877
'sr.recipient_class_id',
874878
'sr.recipient_value',
@@ -888,15 +892,17 @@ private function list(
888892
continue;
889893
}
890894

891-
/** @var non-empty-string $id */
892-
$id = (string)$row['share_id'];
895+
/** @var non-empty-string $recipientId */
896+
$recipientId = (string)$row['id'];
897+
/** @var non-empty-string $shareId */
898+
$shareId = (string)$row['share_id'];
893899
/** @var non-empty-string $initiatorUserId */
894900
$initiatorUserId = $row['initiator_user_id'];
895901
/** @var ?non-empty-string $initiatorInstance */
896902
$initiatorInstance = $row['initiator_instance'];
897903

898904
/** @psalm-suppress PossiblyNullReference The initiator is automatically promoted to the owner, when the initiator is deleted. */
899-
if ($initiatorInstance === null && !$accessContext->overrideChecks && !$shares[$id]['owner']->isCurrentUser(
905+
if ($initiatorInstance === null && !$accessContext->overrideChecks && !$shares[$shareId]['owner']->isCurrentUser(
900906
$accessContext
901907
) && $this->hideDisabledUserShares() && !$this->userManager->get($initiatorUserId)->isEnabled()) {
902908
continue;
@@ -910,7 +916,7 @@ private function list(
910916
/** @var non-empty-string $secret */
911917
$secret = $row['recipient_secret'];
912918

913-
$shares[$id]['recipients'][] = new ShareRecipient(
919+
$shares[$shareId]['recipients'][$recipientId] = new ShareRecipient(
914920
$typeClass,
915921
$value,
916922
$instance,
@@ -921,8 +927,8 @@ private function list(
921927
),
922928
);
923929

924-
$shareRecipientTypeClasses[$id] ??= [];
925-
$shareRecipientTypeClasses[$id][$typeClass] = true;
930+
$shareRecipientTypeClasses[$shareId] ??= [];
931+
$shareRecipientTypeClasses[$shareId][$typeClass] = true;
926932
}
927933
}
928934

@@ -997,9 +1003,9 @@ private function list(
9971003

9981004
$result = $qb->executeQuery();
9991005
foreach ($result->fetchAll() as $row) {
1000-
/** @var non-empty-string $id */
1001-
$id = (string)$row['share_id'];
1002-
if (!isset($shareSourceTypeClasses[$id], $shareRecipientTypeClasses[$id])) {
1006+
/** @var non-empty-string $shareId */
1007+
$shareId = (string)$row['share_id'];
1008+
if (!isset($shareSourceTypeClasses[$shareId], $shareRecipientTypeClasses[$shareId])) {
10031009
continue;
10041010
}
10051011

@@ -1010,13 +1016,13 @@ private function list(
10101016
continue;
10111017
}
10121018

1013-
if (array_intersect($registryPropertyTypeCompatibleSourceTypeClasses[$propertyTypeClass], array_keys($shareSourceTypeClasses[$id])) === []) {
1019+
if (array_intersect($registryPropertyTypeCompatibleSourceTypeClasses[$propertyTypeClass], array_keys($shareSourceTypeClasses[$shareId])) === []) {
10141020
// Skip properties that are currently not compatible, but don't remove them.
10151021
continue;
10161022
}
10171023

10181024
if (array_intersect(
1019-
$registryPropertyTypeCompatibleRecipientTypeClasses[$propertyTypeClass], array_keys($shareRecipientTypeClasses[$id])
1025+
$registryPropertyTypeCompatibleRecipientTypeClasses[$propertyTypeClass], array_keys($shareRecipientTypeClasses[$shareId])
10201026
) === []) {
10211027
// Skip properties that are currently not compatible, but don't remove them.
10221028
continue;
@@ -1030,7 +1036,7 @@ private function list(
10301036
$value = $propertyType->modifyValueOnLoad($value);
10311037
}
10321038

1033-
$shares[$id]['properties'][$propertyTypeClass] = new ShareProperty($propertyTypeClass, $value);
1039+
$shares[$shareId]['properties'][$propertyTypeClass] = new ShareProperty($propertyTypeClass, $value);
10341040
}
10351041
}
10361042

@@ -1052,17 +1058,17 @@ private function list(
10521058

10531059
$result = $qb->executeQuery();
10541060
foreach ($result->fetchAll() as $row) {
1055-
$id = (string)$row['share_id'];
1061+
$shareId = (string)$row['share_id'];
10561062

10571063
/** @var class-string<ISharePermissionType> $permissionTypeClass */
10581064
$permissionTypeClass = $this->classMapper->getClassName((int)$row['permission_class_id']);
1059-
if (!isset($shareCompatiblePermissionTypeClasses[$id][$permissionTypeClass])) {
1065+
if (!isset($shareCompatiblePermissionTypeClasses[$shareId][$permissionTypeClass])) {
10601066
// Skip permissions that are currently not compatible, but don't remove them.
10611067
continue;
10621068
}
10631069

10641070
$enabled = (bool)$row['permission_enabled'];
1065-
$shares[$id]['permissions'][$permissionTypeClass] = new SharePermission($permissionTypeClass, $enabled);
1071+
$shares[$shareId]['permissions'][$permissionTypeClass] = new SharePermission($permissionTypeClass, $enabled);
10661072
}
10671073
}
10681074

@@ -1073,7 +1079,7 @@ private function list(
10731079
$share['state'],
10741080
$share['user_status'],
10751081
$share['sources'],
1076-
$share['recipients'],
1082+
array_values($share['recipients']),
10771083
$share['properties'],
10781084
$share['permissions'],
10791085
), $shares);

0 commit comments

Comments
 (0)