Skip to content

Commit 4d2e022

Browse files
committed
feat(ocm): event on ocm discovery and ocm request
Signed-off-by: Maxence Lange <[email protected]>
1 parent bbca4fe commit 4d2e022

File tree

15 files changed

+261
-57
lines changed

15 files changed

+261
-57
lines changed

apps/cloud_federation_api/appinfo/routes.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@
2525
'url' => '/invite-accepted',
2626
'verb' => 'POST',
2727
'root' => '/ocm',
28-
]
28+
],
29+
30+
// needs to be kept at the bottom of the list
31+
[
32+
'name' => 'OCMRequest#manageOCMRequests',
33+
'url' => '/{ocmPath}',
34+
'requirements' => ['ocmPath' => '.*'],
35+
'verb' => ['GET', 'POST'],
36+
'root' => '/ocm',
37+
],
2938
],
3039
];

apps/cloud_federation_api/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
'OCA\\CloudFederationAPI\\AppInfo\\Application' => $baseDir . '/../lib/AppInfo/Application.php',
1111
'OCA\\CloudFederationAPI\\Capabilities' => $baseDir . '/../lib/Capabilities.php',
1212
'OCA\\CloudFederationAPI\\Config' => $baseDir . '/../lib/Config.php',
13+
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => $baseDir . '/../lib/Controller/OCMRequestController.php',
1314
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => $baseDir . '/../lib/Controller/RequestHandlerController.php',
1415
'OCA\\CloudFederationAPI\\Db\\FederatedInvite' => $baseDir . '/../lib/Db/FederatedInvite.php',
1516
'OCA\\CloudFederationAPI\\Db\\FederatedInviteMapper' => $baseDir . '/../lib/Db/FederatedInviteMapper.php',

apps/cloud_federation_api/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class ComposerStaticInitCloudFederationAPI
2525
'OCA\\CloudFederationAPI\\AppInfo\\Application' => __DIR__ . '/..' . '/../lib/AppInfo/Application.php',
2626
'OCA\\CloudFederationAPI\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php',
2727
'OCA\\CloudFederationAPI\\Config' => __DIR__ . '/..' . '/../lib/Config.php',
28+
'OCA\\CloudFederationAPI\\Controller\\OCMRequestController' => __DIR__ . '/..' . '/../lib/Controller/OCMRequestController.php',
2829
'OCA\\CloudFederationAPI\\Controller\\RequestHandlerController' => __DIR__ . '/..' . '/../lib/Controller/RequestHandlerController.php',
2930
'OCA\\CloudFederationAPI\\Db\\FederatedInvite' => __DIR__ . '/..' . '/../lib/Db/FederatedInvite.php',
3031
'OCA\\CloudFederationAPI\\Db\\FederatedInviteMapper' => __DIR__ . '/..' . '/../lib/Db/FederatedInviteMapper.php',
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\CloudFederationAPI\Controller;
11+
12+
use JsonException;
13+
use OCP\AppFramework\Http;
14+
use OCP\AppFramework\Controller;
15+
use OCP\AppFramework\Http\Attribute\BruteForceProtection;
16+
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
17+
use OCP\AppFramework\Http\Attribute\OpenAPI;
18+
use OCP\AppFramework\Http\Attribute\PublicPage;
19+
use OCP\AppFramework\Http\DataResponse;
20+
use OCP\AppFramework\Http\Response;
21+
use OCP\EventDispatcher\IEventDispatcher;
22+
use OCP\IRequest;
23+
use OCP\OCM\Events\OCMEndpointRequestEvent;
24+
use OCP\OCM\Exceptions\OCMArgumentException;
25+
use Psr\Log\LoggerInterface;
26+
27+
#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)]
28+
class OCMRequestController extends Controller {
29+
public function __construct(
30+
string $appName,
31+
IRequest $request,
32+
private readonly IEventDispatcher $eventDispatcher,
33+
private readonly LoggerInterface $logger,
34+
) {
35+
parent::__construct($appName, $request);
36+
}
37+
38+
#[NoCSRFRequired]
39+
#[PublicPage]
40+
#[BruteForceProtection(action: 'receiveOcmRequest')]
41+
public function manageOCMRequests(string $ocmPath): Response {
42+
try {
43+
json_encode($ocmPath, JSON_THROW_ON_ERROR | JSON_UNESCAPED_SLASHES);
44+
} catch (JsonException) {
45+
throw new OCMArgumentException('path is not UTF-8');
46+
}
47+
48+
$event = new OCMEndpointRequestEvent($this->request->getMethod(), str_replace('//', '/', $ocmPath));
49+
$this->eventDispatcher->dispatchTyped($event);
50+
51+
if ($event->getResponse() === null) {
52+
return new DataResponse('', Http::STATUS_NOT_FOUND);
53+
}
54+
55+
return $event->getResponse();
56+
}
57+
}

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,7 @@
714714
'OCP\\Notification\\InvalidValueException' => $baseDir . '/lib/public/Notification/InvalidValueException.php',
715715
'OCP\\Notification\\NotificationPreloadReason' => $baseDir . '/lib/public/Notification/NotificationPreloadReason.php',
716716
'OCP\\Notification\\UnknownNotificationException' => $baseDir . '/lib/public/Notification/UnknownNotificationException.php',
717+
'OCP\\OCM\\Events\\LocalOCMDiscoveryEvent' => $baseDir . '/lib/public/OCM/Events/LocalOCMDiscoveryEvent.php',
717718
'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => $baseDir . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php',
718719
'OCP\\OCM\\Exceptions\\OCMArgumentException' => $baseDir . '/lib/public/OCM/Exceptions/OCMArgumentException.php',
719720
'OCP\\OCM\\Exceptions\\OCMProviderException' => $baseDir . '/lib/public/OCM/Exceptions/OCMProviderException.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
755755
'OCP\\Notification\\InvalidValueException' => __DIR__ . '/../../..' . '/lib/public/Notification/InvalidValueException.php',
756756
'OCP\\Notification\\NotificationPreloadReason' => __DIR__ . '/../../..' . '/lib/public/Notification/NotificationPreloadReason.php',
757757
'OCP\\Notification\\UnknownNotificationException' => __DIR__ . '/../../..' . '/lib/public/Notification/UnknownNotificationException.php',
758+
'OCP\\OCM\\Events\\LocalOCMDiscoveryEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/LocalOCMDiscoveryEvent.php',
758759
'OCP\\OCM\\Events\\ResourceTypeRegisterEvent' => __DIR__ . '/../../..' . '/lib/public/OCM/Events/ResourceTypeRegisterEvent.php',
759760
'OCP\\OCM\\Exceptions\\OCMArgumentException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMArgumentException.php',
760761
'OCP\\OCM\\Exceptions\\OCMProviderException' => __DIR__ . '/../../..' . '/lib/public/OCM/Exceptions/OCMProviderException.php',

lib/private/AppFramework/Routing/RouteParser.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ private function processRoute(array $route, string $appName, string $routeNamePr
7575
$root = $this->buildRootPrefix($route, $appName, $routeNamePrefix);
7676

7777
$url = $root . '/' . ltrim($route['url'], '/');
78-
$verb = strtoupper($route['verb'] ?? 'GET');
7978

8079
$split = explode('#', $name, 3);
8180
if (count($split) !== 2) {
@@ -95,7 +94,7 @@ private function processRoute(array $route, string $appName, string $routeNamePr
9594
$routeName = strtolower($routeNamePrefix . $appName . '.' . $controller . '.' . $action . $postfix);
9695

9796
$routeObject = new Route($url);
98-
$routeObject->method($verb);
97+
$routeObject->method((array) ($route['verb'] ?? ['GET']));
9998

10099
// optionally register requirements for route. This is used to
101100
// tell the route parser how url parameters should be matched
@@ -174,7 +173,6 @@ private function processResources(array $resources, string $appName, string $rou
174173
$url = $root . '/' . ltrim($config['url'], '/');
175174
$method = $action['name'];
176175

177-
$verb = strtoupper($action['verb'] ?? 'GET');
178176
$collectionAction = $action['on-collection'] ?? false;
179177
if (!$collectionAction) {
180178
$url .= '/{id}';
@@ -188,7 +186,7 @@ private function processResources(array $resources, string $appName, string $rou
188186
$routeName = $routeNamePrefix . $appName . '.' . strtolower($resource) . '.' . $method;
189187

190188
$route = new Route($url);
191-
$route->method($verb);
189+
$route->method((array) ($action['verb'] ?? ['GET']));
192190

193191
$route->defaults(['caller' => [$appName, $controllerName, $actionName]]);
194192

lib/private/OCM/Model/OCMProvider.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ public function getProvider(): string {
124124
* @return $this
125125
*/
126126
public function setCapabilities(array $capabilities): static {
127-
foreach ($capabilities as $value) {
128-
if (!in_array($value, $this->capabilities)) {
129-
array_push($this->capabilities, $value);
130-
}
131-
}
127+
// since ocm 1.2, removing slashes from capabilities
128+
$capabilities = array_map(static function (string $capability): string {
129+
return ltrim($capability, '/');
130+
}, $capabilities);
132131

132+
$this->capabilities = array_unique(array_merge($this->capabilities, $capabilities));
133133
return $this;
134134
}
135135

@@ -139,6 +139,7 @@ public function setCapabilities(array $capabilities): static {
139139
public function getCapabilities(): array {
140140
return $this->capabilities;
141141
}
142+
142143
/**
143144
* create a new resource to later add it with {@see IOCMProvider::addResourceType()}
144145
* @return IOCMResource

lib/private/OCM/OCMDiscoveryService.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
use OCP\ICacheFactory;
2424
use OCP\IConfig;
2525
use OCP\IURLGenerator;
26+
use OCP\OCM\Events\LocalOCMDiscoveryEvent;
2627
use OCP\OCM\Events\ResourceTypeRegisterEvent;
2728
use OCP\OCM\Exceptions\OCMProviderException;
2829
use OCP\OCM\ICapabilityAwareOCMProvider;
@@ -176,7 +177,7 @@ public function getLocalOCMProvider(bool $fullDetails = true): ICapabilityAwareO
176177
$provider->setEnabled(true);
177178
$provider->setApiVersion(self::API_VERSION);
178179
$provider->setEndPoint(substr($url, 0, $pos));
179-
$provider->setCapabilities(['/invite-accepted', '/notifications', '/shares']);
180+
$provider->setCapabilities(['invite-accepted', 'notifications', 'shares']);
180181

181182
// The inviteAcceptDialog is available from the contacts app, if this config value is set
182183
$inviteAcceptDialog = $this->appConfig->getValueString('core', ConfigLexicon::OCM_INVITE_ACCEPT_DIALOG);
@@ -207,6 +208,10 @@ public function getLocalOCMProvider(bool $fullDetails = true): ICapabilityAwareO
207208
}
208209
}
209210

211+
$event = new LocalOCMDiscoveryEvent($provider);
212+
$this->eventDispatcher->dispatchTyped($event);
213+
214+
// deprecated since 33.0.0
210215
$event = new ResourceTypeRegisterEvent($provider);
211216
$this->eventDispatcher->dispatchTyped($event);
212217

lib/private/Route/Route.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Route extends SymfonyRoute implements IRoute {
1414
/**
1515
* Specify the method when this route is to be used
1616
*
17-
* @param string $method HTTP method (uppercase)
17+
* @param string|array $method HTTP method
1818
* @return \OC\Route\Route
1919
*/
2020
public function method($method) {

0 commit comments

Comments
 (0)