Skip to content

Unified Sharing Legacy Sync - #65972

Draft
provokateurin wants to merge 21 commits into
masterfrom
unified-sharing-legacy-sync
Draft

provokateurin wants to merge 21 commits into
masterfrom
unified-sharing-legacy-sync

Conversation

@provokateurin

Copy link
Copy Markdown
Member

#64737

There are some TODOs left in the code, but I just need to get this merged, so future changes can be done in smaller PRs.

The syncing logic is not nice to understand, because it's an encoding of all the quirks and limitations the legacy sharing system has. I tried my best to leave useful comments whenever possible, but I'm happy to add more if there are questions during the review.

@provokateurin provokateurin added this to the Nextcloud 36 milestone Oct 27, 2026
@provokateurin provokateurin self-assigned this Oct 27, 2026
Comment thread apps/federatedfilesharing/lib/FederatedShareProvider.php Outdated

$sourceNodeTargetTable = $schema->createTable('sharing_source_node_target');
$sourceNodeTargetTable->addColumn('user_id', Types::TEXT, ['length' => 64]);
$sourceNodeTargetTable->addColumn('source_instance', Types::STRING, ['length' => 128, 'notnull' => false]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this and any code using it will need to be adjusted once #65512 is in


#[Override]
public function handle(Event $event): void {
foreach ($event->shareIds as $shareId) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we send the share objects with the event to prevent having to re-fetch them here.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that in the place where the event is emitted the share is from the perspective of the user. At least in the sync part we need to fetch the full share. I only sent the IDs, to avoid this kind of confusion, because listeners would likely assume that they see the full share.

So I would like to keep it like this to make sure the event is not used in the wrong way. Alternatively the shares could be re-fetched before the event is emitted, so the case of multiple listeners would be optimized, because they don't need to fetch the shares each.

Comment thread apps/files/lib/Sharing/SourceNodeTargetManager.php Outdated
Comment thread apps/files/lib/Sharing/SharesUpdatedListener.php Outdated
/**
* Get user ids for a recipient value.
*
* @return list<string>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer list<IUser>

Comment thread lib/private/Share20/Manager.php

$legacyMappingTable = $schema->createTable('sharing_share_legacy_mapping');
$legacyMappingTable->addColumn('id', Types::BIGINT);
$legacyMappingTable->addColumn('legacy_provider', Types::STRING, ['length' => 128]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use class names and the class-mapper so we can store this as ints?

$legacyMappingTable->addColumn('recipient_secrets', Types::TEXT);
$legacyMappingTable->addColumn('recipient_value', Types::STRING, ['length' => 255]);
$legacyMappingTable->setPrimaryKey(['legacy_provider', 'legacy_id']);
$legacyMappingTable->addIndex(['id']);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is id + recipient_value unique? if so, we should probably have an index for it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it's not.

* @experimental 35.0.0
*/
public function getCreatedAt(): DateTimeImmutable {
return $this->createdAt ??= Server::get(ISnowflakeDecoder::class)->decode($this->id)->getCreatedAt();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inject the decoder in the constructor instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's better to only lookup the class once when needed and not every time a Share object is instantiated. The result is cached anyway, so the class won't be looked up twice if the method is called twice.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Share objects are manually constructed by the backend right, not automatically constructed. So the backend only needs to lookup the decoder once

}

// TODO: Test
public function mapLegacyShares(?IUser $user, ?int $limit = null): void {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapUnmappedLegacyShares to make it more clear that it doesn't update existing mappings

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove that code for now, because it's neither used nor tested yet.

Comment on lines +169 to +178
$legacyMapping = $this->legacyMapper->createLegacyMapping(
$id,
$provider,
$row['id'],
new DateTimeImmutable(),
[$this->getSharingManager()->generateSecret()],
$this->getSharingManager()->generateSecret(),
);

$this->syncLegacySharesToShare($id, [$legacyMapping]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these two should be in a transaction to prevent an error halfway from causing a desync

if ($event instanceof SharesUpdatedEvent) {
foreach ($event->shareIds as $id) {
$this->wrapSync($id, function () use ($id): void {
$share = $this->getSharingManager()->getShare(new ShareAccessContext(overrideChecks: true), $id);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another place where having the share in the event would save work

Comment on lines +447 to +450
new ShareUser(
$shareInitiator['value'],
$shareInitiator['instance'],
),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor nitpick: creating the ShareUser can be de-duplicated

Comment on lines +914 to +918
$this->ignoreNewLegacyShare = false;
} catch (Exception $exception) {
$this->ignoreNewLegacyShare = false;
throw $exception;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

} finally {
    $this->ignoreNewLegacyShare = false;
}

… the controller

Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
… a hash already

Signed-off-by: provokateurin <kate@provokateurin.de>
…ead of load

Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
…ailable

Signed-off-by: provokateurin <kate@provokateurin.de>
…licit recipients

Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
Signed-off-by: provokateurin <kate@provokateurin.de>
@provokateurin
provokateurin force-pushed the unified-sharing-legacy-sync branch from 2279e86 to 6fad6c3 Compare October 28, 2026 14:06

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants