From 123e22808201e2483dd6f983802ff60db8a195dc Mon Sep 17 00:00:00 2001 From: provokateurin Date: Wed, 13 Nov 2024 08:18:34 +0100 Subject: [PATCH] fix(OCS): Fix route vs Controller differences Signed-off-by: provokateurin --- generate-spec | 30 ++++++----- tests/openapi-administration.json | 86 +++++++++++++++++++++++++++++-- tests/openapi-full.json | 86 +++++++++++++++++++++++++++++-- 3 files changed, 184 insertions(+), 18 deletions(-) diff --git a/generate-spec b/generate-spec index d700c90..6c07e91 100755 --- a/generate-spec +++ b/generate-spec @@ -334,12 +334,11 @@ if (count($parsedRoutes) === 0) { $operationIds = []; foreach ($parsedRoutes as $key => $value) { - $isOCS = $key === 'ocs'; - $isIndex = $key === 'routes'; - - if (!$isOCS && !$isIndex) { - continue; - } + $pathPrefix = match ($key) { + 'ocs' => '/ocs/v2.php', + 'routes' => '/index.php', + default => throw new \InvalidArgumentException('Unknown routes key "' . $key . '"'), + }; foreach ($value as $route) { $routeName = $route['name']; @@ -356,12 +355,7 @@ foreach ($parsedRoutes as $key => $value) { if (str_ends_with($url, '/')) { $url = substr($url, 0, -1); } - if ($isIndex) { - $url = '/index.php' . $root . $url; - } - if ($isOCS) { - $url = '/ocs/v2.php' . $root . $url; - } + $url = $pathPrefix . $root . $url; $methodName = lcfirst(str_replace('_', '', ucwords(explode('#', $routeName)[1], '_'))); if ($methodName == 'preflightedCors') { @@ -382,6 +376,18 @@ foreach ($parsedRoutes as $key => $value) { continue; } + $parentControllerClass = $controllerClass->extends?->name ?? ''; + $parentControllerClass = explode('\\', $parentControllerClass); + $parentControllerClass = end($parentControllerClass); + // This is very ugly, but since we do not parse the entire source code we can not say with certainty which controller type is used. + // To still allow apps to use custom controllers that extend OCSController, we only check the suffix and have the warning if the controller type can not be detected. + $isOCS = str_ends_with($parentControllerClass, 'OCSController'); + if ($parentControllerClass !== 'Controller' && $parentControllerClass !== 'ApiController' && $parentControllerClass !== 'OCSController' && !$isOCS) { + Logger::warning($routeName, 'You are extending a custom controller class. Make sure that it ends with "OCSController" if it extends "OCSController" itself.'); + } elseif ($isOCS !== ($pathPrefix === '/ocs/v2.php')) { + Logger::warning($routeName, 'Do not mix OCS/non-OCS routes and non-OCS/OCS controllers!'); + } + $controllerScopes = Helpers::getOpenAPIAttributeScopes($controllerClass, $routeName); if (Helpers::classMethodHasAnnotationOrAttribute($controllerClass, 'IgnoreOpenAPI')) { if (count($controllerScopes) === 0 || (in_array('ignore', $controllerScopes, true) && count($controllerScopes) === 1)) { diff --git a/tests/openapi-administration.json b/tests/openapi-administration.json index 737a42d..af789e3 100644 --- a/tests/openapi-administration.json +++ b/tests/openapi-administration.json @@ -4625,6 +4625,16 @@ "pattern": "^[a-z]+$", "default": "abc" } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } } ], "responses": { @@ -4632,7 +4642,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } } @@ -4663,6 +4693,16 @@ "pattern": "^[a-z]+$", "default": "abc" } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } } ], "responses": { @@ -4670,7 +4710,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } } @@ -4718,7 +4778,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } } diff --git a/tests/openapi-full.json b/tests/openapi-full.json index a5dbf1b..b126626 100644 --- a/tests/openapi-full.json +++ b/tests/openapi-full.json @@ -4775,6 +4775,16 @@ "pattern": "^[a-z]+$", "default": "abc" } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } } ], "responses": { @@ -4782,7 +4792,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } } @@ -4813,6 +4843,16 @@ "pattern": "^[a-z]+$", "default": "abc" } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } } ], "responses": { @@ -4820,7 +4860,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } } @@ -4868,7 +4928,27 @@ "description": "Success", "content": { "application/json": { - "schema": {} + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } } } }