From 79e8608bd198b2c8ff51b450437fea108bb14330 Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Tue, 9 Jun 2026 21:59:45 +0200 Subject: [PATCH 1/2] fix(ocm): merge resource types by name in discovery Current code blindy adds any resources to the ocm disocvery, this makes it so that different cloud federation providers can not add different protocols for the same resourceType without the resourceType being duplicated, something that OCM does not allow: ``` REQUIRED: resourceTypes (array) - A list of all resource types this server supports in both the Sending Server role and the Receiving Server role, with their access protocols. Each item in this list MUST itself be an object containing the following fields: name (string) - A supported resource type (file, calendar, contact, ...). Implementations MUST offer support for at least one resource type, where file is the commonly supported one. Each resource type is identified by its name: the list MUST NOT contain more than one resource type object per given name. ... ``` https://datatracker.ietf.org/doc/html/draft-ietf-ocm-open-cloud-mesh-04#name-fields This patch changes this behaviour from this example result: ``` { "name": "folder", "shareTypes": [ "user" ], "protocols": { "webapp": {} } }, { "name": "folder", "shareTypes": [ "user" ], "protocols": { "webapp-receive": { "targets": [ "blank", "iframe" ] } } ``` to: ``` { "name": "folder", "shareTypes": [ "user" ], "protocols": { "webapp": {}, "webapp-receive": { "targets": [ "blank", "iframe" ] } } ``` which is the correct behaviour according to OCM. Signed-off-by: Micke Nordin --- lib/private/OCM/Model/OCMProvider.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/private/OCM/Model/OCMProvider.php b/lib/private/OCM/Model/OCMProvider.php index 6c1591013a7a3..899cb73aea415 100644 --- a/lib/private/OCM/Model/OCMProvider.php +++ b/lib/private/OCM/Model/OCMProvider.php @@ -179,6 +179,21 @@ public function createNewResourceType(): IOCMResource { */ #[\Override] public function addResourceType(IOCMResource $resource): static { + foreach ($this->resourceTypes as $existing) { + if ($existing->getName() === $resource->getName()) { + $existing->setShareTypes(array_values(array_unique( + array_merge( + $existing->getShareTypes(), + $resource->getShareTypes() + ) + ))); + $existing->setProtocols(array_merge( + $existing->getProtocols(), + $resource->getProtocols() + )); + return $this; + } + } $this->resourceTypes[] = $resource; return $this; From d5c56b80be400ffdb0a99dfd40b577853d104d2a Mon Sep 17 00:00:00 2001 From: Micke Nordin Date: Tue, 9 Jun 2026 22:37:26 +0200 Subject: [PATCH 2/2] tests: Add tests for deduplication of resourceTypes Assisted-by: ClaudeCode:claude-fable-5 Signed-off-by: Micke Nordin --- tests/lib/OCM/OCMProviderTest.php | 72 +++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 tests/lib/OCM/OCMProviderTest.php diff --git a/tests/lib/OCM/OCMProviderTest.php b/tests/lib/OCM/OCMProviderTest.php new file mode 100644 index 0000000000000..bae2abef9a8b4 --- /dev/null +++ b/tests/lib/OCM/OCMProviderTest.php @@ -0,0 +1,72 @@ +provider = new OCMProvider(); + } + + private function resource(string $name, array $shareTypes, array $protocols): IOCMResource { + $resource = $this->provider->createNewResourceType(); + $resource->setName($name) + ->setShareTypes($shareTypes) + ->setProtocols($protocols); + return $resource; + } + + public function testAddResourceTypeKeepsDistinctNames(): void { + $this->provider->addResourceType($this->resource('file', ['user'], ['webdav' => '/dav/'])); + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp' => []])); + + $this->assertCount(2, $this->provider->getResourceTypes()); + } + + public function testAddResourceTypeMergesSameName(): void { + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp' => []])); + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp-receive' => ['targets' => ['blank', 'iframe']]])); + + $resourceTypes = $this->provider->getResourceTypes(); + $this->assertCount(1, $resourceTypes); + $this->assertSame( + ['webapp' => [], 'webapp-receive' => ['targets' => ['blank', 'iframe']]], + $resourceTypes[0]->getProtocols(), + ); + } + + public function testAddResourceTypeDedupesShareTypes(): void { + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp' => []])); + $this->provider->addResourceType($this->resource('folder', ['user', 'group'], ['webapp-receive' => []])); + + $shareTypes = $this->provider->getResourceTypes()[0]->getShareTypes(); + $this->assertSame(['user', 'group'], $shareTypes); + // Deduplication must not leave key gaps, or shareTypes would + // serialize as a JSON object instead of an array. + $this->assertSame('["user","group"]', json_encode($shareTypes)); + } + + public function testAddResourceTypeMergeOverwritesSameProtocol(): void { + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp' => ['a' => 1]])); + $this->provider->addResourceType($this->resource('folder', ['user'], ['webapp' => ['b' => 2]])); + + $this->assertSame( + ['webapp' => ['b' => 2]], + $this->provider->getResourceTypes()[0]->getProtocols(), + ); + } +}