From f0f5b55d2bdff6692bedc8b20f07b28e02e7325e Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Sat, 28 Oct 2023 17:33:51 +0200 Subject: [PATCH 1/5] feat(tests): Add a demo app for testing Signed-off-by: Joas Schilling --- .editorconfig | 14 + tests/appinfo/info.xml | 52 + tests/appinfo/routes.php | 42 + .../Controller/AdminSettingsController.php | 69 ++ tests/lib/Controller/SettingsController.php | 164 +++ tests/lib/ResponseDefinitions.php | 75 ++ tests/openapi.json | 934 ++++++++++++++++++ 7 files changed, 1350 insertions(+) create mode 100644 .editorconfig create mode 100644 tests/appinfo/info.xml create mode 100644 tests/appinfo/routes.php create mode 100644 tests/lib/Controller/AdminSettingsController.php create mode 100644 tests/lib/Controller/SettingsController.php create mode 100644 tests/lib/ResponseDefinitions.php create mode 100644 tests/openapi.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..35630aa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# https://editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/tests/appinfo/info.xml b/tests/appinfo/info.xml new file mode 100644 index 0000000..7147b0e --- /dev/null +++ b/tests/appinfo/info.xml @@ -0,0 +1,52 @@ + + + notifications + Notifications + + + + 2.16.0 + agpl + Joas Schilling + + + + + + tools + + https://github.com/nextcloud/notifications + https://github.com/nextcloud/notifications/issues + https://github.com/nextcloud/notifications.git + + + + + + + OCA\Notifications\BackgroundJob\GenerateUserSettings + OCA\Notifications\BackgroundJob\SendNotificationMails + + + + OCA\Notifications\Command\Generate + OCA\Notifications\Command\TestPush + + + + OCA\Notifications\Settings\Admin + OCA\Notifications\Settings\AdminSection + OCA\Notifications\Settings\Personal + OCA\Notifications\Settings\PersonalSection + + diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php new file mode 100644 index 0000000..bda23d9 --- /dev/null +++ b/tests/appinfo/routes.php @@ -0,0 +1,42 @@ + + * @copyright Copyright (c) 2016, ownCloud, Inc. + * + * @author Joas Schilling + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +return [ + 'ocs' => [ + ['name' => 'AdminSettings#adminScopeImplicitFromAdminRequired', 'url' => '/api/{apiVersion}/default-admin', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'AdminSettings#movedToDefaultScope', 'url' => '/api/{apiVersion}/default-admin-overwritten', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'AdminSettings#movedToSettingsTag', 'url' => '/api/{apiVersion}/moved-with-tag', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + + ['name' => 'Settings#federationByController', 'url' => '/api/{apiVersion}/controller-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#ignoreByDeprecatedAttributeOnMethod', 'url' => '/api/{apiVersion}/ignore-openapi-attribute', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#ignoreByScopeOnMethod', 'url' => '/api/{apiVersion}/ignore-method-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#movedToDefaultScope', 'url' => '/api/{apiVersion}/default-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#movedToAdminScope', 'url' => '/api/{apiVersion}/admin-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#defaultAndAdminScope', 'url' => '/api/{apiVersion}/default-and-admin-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#nestedSchemas', 'url' => '/api/{apiVersion}/nested-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#listSchemas', 'url' => '/api/{apiVersion}/list-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ], +]; diff --git a/tests/lib/Controller/AdminSettingsController.php b/tests/lib/Controller/AdminSettingsController.php new file mode 100644 index 0000000..f3fbd72 --- /dev/null +++ b/tests/lib/Controller/AdminSettingsController.php @@ -0,0 +1,69 @@ + + * + * @author Julien Barnoin + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Notifications\Controller; + +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\OpenAPI; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; + +class AdminSettingsController extends OCSController { + /** + * Route is only in the admin scope because there is no "NoAdminRequired" annotation or attribute + * + * @return DataResponse, array{}> + * + * 200: Personal settings updated + */ + public function adminScopeImplicitFromAdminRequired(): DataResponse { + return new DataResponse(); + } + + /** + * Route is in the default scope because the method overwrites with the Attribute + * + * @return DataResponse, array{}> + * + * 200: Personal settings updated + */ + #[OpenAPI] + public function movedToDefaultScope(): DataResponse { + return new DataResponse(); + } + + /** + * Route in default scope with tags + * + * @return DataResponse, array{}> + * + * 200: Personal settings updated + */ + #[OpenAPI(tags: ['settings', 'admin-settings'])] + public function movedToSettingsTag(): DataResponse { + return new DataResponse(); + } +} diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php new file mode 100644 index 0000000..efd8c3a --- /dev/null +++ b/tests/lib/Controller/SettingsController.php @@ -0,0 +1,164 @@ + + * + * @author Julien Barnoin + * + * @license AGPL-3.0-or-later + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Notifications\Controller; + +use OCA\Notifications\ResponseDefinitions; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\IgnoreOpenAPI; +use OCP\AppFramework\Http\Attribute\OpenAPI; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; + +/** + * @psalm-import-type NotificationsPushDevice from ResponseDefinitions + * @psalm-import-type NotificationsNotification from ResponseDefinitions + * @psalm-import-type NotificationsCollection from ResponseDefinitions + */ +#[OpenAPI(scope: OpenAPI::SCOPE_FEDERATION)] +class SettingsController extends OCSController { + + /** + * @NoAdminRequired + * + * Route is ignored because of scope on the controller + * + * @return DataResponse, array{}> + * + * 200: OK + */ + public function federationByController(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is ignored because of IgnoreOpenAPI attribute on the method + * + * @return DataResponse, array{}> + * + * 200: OK + */ + #[IgnoreOpenAPI] + public function ignoreByDeprecatedAttributeOnMethod(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is ignored because of scope on the method + * + * @return DataResponse, array{}> + * + * 200: OK + */ + #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] + public function ignoreByScopeOnMethod(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is only in the default scope + * + * @return DataResponse, array{}> + * + * 200: Personal settings updated + */ + #[OpenAPI] + public function movedToDefaultScope(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is only in the admin scope due to defined scope + * + * @return DataResponse + * + * 200: Admin settings updated + */ + #[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)] + public function movedToAdminScope(): DataResponse { + return new DataResponse($this->createNotificationsPushDevice()); + } + + /** + * @return NotificationsPushDevice + */ + protected function createNotificationsPushDevice(): array { + return [ + 'publicKey' => 'publicKey', + 'deviceIdentifier' => 'deviceIdentifier', + 'signature' => 'signature', + ]; + } + + /** + * @NoAdminRequired + * + * Route is in admin and default scope + * + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + #[OpenAPI] + #[OpenAPI(scope: OpenAPI::SCOPE_ADMINISTRATION)] + public function defaultAndAdminScope(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is ignored because of scope on the controller + * + * @return DataResponse, array{}> + * + * 200: OK + */ + public function nestedSchemas(): DataResponse { + return new DataResponse(); + } + + /** + * @NoAdminRequired + * + * Route is ignored because of scope on the controller + * + * @return DataResponse + * + * 200: OK + */ + public function listSchemas(): DataResponse { + return new DataResponse(); + } +} diff --git a/tests/lib/ResponseDefinitions.php b/tests/lib/ResponseDefinitions.php new file mode 100644 index 0000000..88b1b21 --- /dev/null +++ b/tests/lib/ResponseDefinitions.php @@ -0,0 +1,75 @@ + + * + * @author Kate Döen + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Notifications; + +/** + * @psalm-type NotificationsItem = array{ + * label: string, + * link: string, + * type: string, + * primary: bool, + * } + * + * @psalm-type NotificationsCollection = list + * + * @psalm-type NotificationsNotificationAction = array{ + * label: string, + * link: string, + * type: string, + * primary: bool, + * } + * + * @psalm-type NotificationsNotification = array{ + * notification_id: int, + * app: string, + * user: string, + * datetime: string, + * object_type: string, + * object_id: string, + * subject: string, + * message: string, + * link: string, + * actions: NotificationsNotificationAction[], + * subjectRich?: string, + * subjectRichParameters?: array, + * messageRich?: string, + * messageRichParameters?: array, + * icon?: string, + * shouldNotify?: bool, + * } + * + * @psalm-type NotificationsPushDeviceBase = array{ + * deviceIdentifier: string, + * } + * + * @psalm-type NotificationsPushDevice = NotificationsPushDeviceBase&array{ + * publicKey: string, + * signature: string, + * } + */ +class ResponseDefinitions { +} diff --git a/tests/openapi.json b/tests/openapi.json new file mode 100644 index 0000000..f125dac --- /dev/null +++ b/tests/openapi.json @@ -0,0 +1,934 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "notifications", + "version": "0.0.1", + "description": "This app provides a backend and frontend for the notification API available in Nextcloud.", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "Collection": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Item" + } + }, + "Item": { + "type": "object", + "required": [ + "label", + "link", + "type", + "primary" + ], + "properties": { + "label": { + "type": "string" + }, + "link": { + "type": "string" + }, + "type": { + "type": "string" + }, + "primary": { + "type": "boolean" + } + } + }, + "Notification": { + "type": "object", + "required": [ + "notification_id", + "app", + "user", + "datetime", + "object_type", + "object_id", + "subject", + "message", + "link", + "actions" + ], + "properties": { + "notification_id": { + "type": "integer", + "format": "int64" + }, + "app": { + "type": "string" + }, + "user": { + "type": "string" + }, + "datetime": { + "type": "string" + }, + "object_type": { + "type": "string" + }, + "object_id": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "message": { + "type": "string" + }, + "link": { + "type": "string" + }, + "actions": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationAction" + } + }, + "subjectRich": { + "type": "string" + }, + "subjectRichParameters": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "messageRich": { + "type": "string" + }, + "messageRichParameters": { + "type": "object", + "additionalProperties": { + "type": "object" + } + }, + "icon": { + "type": "string" + }, + "shouldNotify": { + "type": "boolean" + } + } + }, + "NotificationAction": { + "type": "object", + "required": [ + "label", + "link", + "type", + "primary" + ], + "properties": { + "label": { + "type": "string" + }, + "link": { + "type": "string" + }, + "type": { + "type": "string" + }, + "primary": { + "type": "boolean" + } + } + }, + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + }, + "PushDevice": { + "allOf": [ + { + "$ref": "#/components/schemas/PushDeviceBase" + }, + { + "type": "object", + "required": [ + "publicKey", + "signature" + ], + "properties": { + "publicKey": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + } + ] + }, + "PushDeviceBase": { + "type": "object", + "required": [ + "deviceIdentifier" + ], + "properties": { + "deviceIdentifier": { + "type": "string" + } + } + } + } + }, + "paths": { + "/ocs/v2.php/apps/notifications/api/{apiVersion}/default-admin": { + "post": { + "operationId": "admin_settings-admin-scope-implicit-from-admin-required", + "summary": "Route is only in the admin scope because there is no \"NoAdminRequired\" annotation or attribute", + "description": "This endpoint requires admin access", + "tags": [ + "admin_settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Personal settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/default-admin-overwritten": { + "post": { + "operationId": "admin_settings-moved-to-default-scope", + "summary": "Route is in the default scope because the method overwrites with the Attribute", + "description": "This endpoint requires admin access", + "tags": [ + "admin_settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Personal settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/moved-with-tag": { + "post": { + "operationId": "admin_settings-moved-to-settings-tag", + "summary": "Route in default scope with tags", + "description": "This endpoint requires admin access", + "tags": [ + "admin_settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Personal settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/controller-scope": { + "post": { + "operationId": "settings-federation-by-controller", + "summary": "Route is ignored because of scope on the controller", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/ignore-method-scope": { + "post": { + "operationId": "settings-ignore-by-scope-on-method", + "summary": "Route is ignored because of scope on the method", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/default-scope": { + "post": { + "operationId": "settings-moved-to-default-scope", + "summary": "Route is only in the default scope", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Personal settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/admin-scope": { + "post": { + "operationId": "settings-moved-to-admin-scope", + "summary": "Route is only in the admin scope due to defined scope", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/PushDevice" + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/default-and-admin-scope": { + "post": { + "operationId": "settings-default-and-admin-scope", + "summary": "Route is in admin and default scope", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/nested-schemas": { + "post": { + "operationId": "settings-nested-schemas", + "summary": "Route is ignored because of scope on the controller", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Notification" + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/list-schemas": { + "post": { + "operationId": "settings-list-schemas", + "summary": "Route is ignored because of scope on the controller", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Collection" + } + } + } + } + } + } + } + } + } + } + } + }, + "tags": [] +} \ No newline at end of file From 3fd989c3d1a3568f82e12a7d69d5499d67223edb Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Wed, 8 Nov 2023 17:14:02 +0100 Subject: [PATCH 2/5] feat(CI): Add basic CI Signed-off-by: Joas Schilling --- .github/workflows/lint-php.yml | 60 +++++++++++++++++++++++++ .github/workflows/pr-feedback.yml | 34 ++++++++++++++ .github/workflows/test.yml | 75 +++++++++++++++++++++++++++++++ composer.json | 53 ++++++++++++---------- 4 files changed, 198 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/lint-php.yml create mode 100644 .github/workflows/pr-feedback.yml create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/lint-php.yml b/.github/workflows/lint-php.yml new file mode 100644 index 0000000..c624cc1 --- /dev/null +++ b/.github/workflows/lint-php.yml @@ -0,0 +1,60 @@ +# This workflow is provided via the organization template repository +# +# https://github.com/nextcloud/.github +# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization + +name: Lint php + +on: + pull_request: + push: + branches: + - main + - master + - stable* + +permissions: + contents: read + +concurrency: + group: lint-php-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + php-lint: + runs-on: ubuntu-latest + strategy: + matrix: + php-versions: [ "8.1" ] + + name: php-lint + + steps: + - name: Checkout + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + + - name: Set up php ${{ matrix.php-versions }} + uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + ini-file: development + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Lint + run: composer run lint + + summary: + permissions: + contents: none + runs-on: ubuntu-latest + needs: php-lint + + if: always() + + name: php-lint-summary + + steps: + - name: Summary status + run: if ${{ needs.php-lint.result != 'success' && needs.php-lint.result != 'skipped' }}; then exit 1; fi diff --git a/.github/workflows/pr-feedback.yml b/.github/workflows/pr-feedback.yml new file mode 100644 index 0000000..46eaff9 --- /dev/null +++ b/.github/workflows/pr-feedback.yml @@ -0,0 +1,34 @@ +# This workflow is provided via the organization template repository +# +# https://github.com/nextcloud/.github +# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization + +name: 'Ask for feedback on PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + pr-feedback: + runs-on: ubuntu-latest + steps: + - name: The get-github-handles-from-website action + uses: marcelklehr/get-github-handles-from-website-action@a739600f6b91da4957f51db0792697afbb2f143c # v1.0.0 + id: scrape + with: + website: 'https://nextcloud.com/team/' + - uses: marcelklehr/pr-feedback-action@601109aa729eb4c8d6d0ece7567b9d4901db4aef + with: + feedback-message: | + Hello there, + Thank you so much for taking the time and effort to create a pull request to our Nextcloud project. + + We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. + + Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 + + Thank you for contributing to Nextcloud and we hope to hear from you soon! + days-before-feedback: 14 + start-date: "2023-11-08" + exempt-authors: "${{ steps.scrape.outputs.users }},nextcloud-command,nextcloud-android-bot" + exempt-bots: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a8984e9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,75 @@ +# This workflow is provided via the organization template repository +# +# https://github.com/nextcloud/.github +# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization + +name: Generate OpenAPI + +on: + pull_request: + push: + branches: + - main + - master + - stable* + +permissions: + contents: read + +concurrency: + group: openapi-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + openapi: + runs-on: ubuntu-latest + strategy: + matrix: + php-versions: [ "8.1" ] + + name: openapi + + steps: + - name: Checkout + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + + - name: Set up php ${{ matrix.php-versions }} + uses: shivammathur/setup-php@4bd44f22a98a19e0950cbad5f31095157cc9621b # v2 + with: + php-version: ${{ matrix.php-versions }} + coverage: none + ini-file: development + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Install dependencies + run: composer i + + - name: Generate OpenAPI + working-directory: tests/ + run: ../generate-spec + + - name: Check openapi changes + run: | + bash -c "[[ ! \"`git status --porcelain `\" ]] || (echo 'Please recompile and commit the assets, see the section \"Show changes on failure\" for details' && exit 1)" + + - name: Show changes on failure + if: failure() + run: | + git status + git --no-pager diff + exit 1 # make it red to grab attention + + summary: + permissions: + contents: none + runs-on: ubuntu-latest + needs: openapi + + if: always() + + name: openapi-summary + + steps: + - name: Summary status + run: if ${{ needs.openapi.result != 'success' && needs.openapi.result != 'skipped' }}; then exit 1; fi diff --git a/composer.json b/composer.json index 4a93196..a57585e 100644 --- a/composer.json +++ b/composer.json @@ -1,26 +1,31 @@ { - "name": "nextcloud/openapi-extractor", - "require": { - "php": "^8.1", - "ext-simplexml": "*", - "nikic/php-parser": "^4.16", - "adhocore/cli": "^v1.6", - "phpstan/phpdoc-parser": "^1.23" - }, - "require-dev": { - "nextcloud/coding-standard": "^1.1" - }, - "bin": [ - "generate-spec", - "merge-specs" - ], - "autoload": { - "psr-4": { - "OpenAPIExtractor\\": "src" - } - }, - "scripts": { - "cs:check": "php-cs-fixer fix --dry-run --diff", - "cs:fix": "php-cs-fixer fix" - } + "name": "nextcloud/openapi-extractor", + "bin": [ + "generate-spec", + "merge-specs" + ], + "config": { + "sort-packages": true + }, + "autoload": { + "psr-4": { + "OpenAPIExtractor\\": "src" + } + }, + "require": { + "php": "^8.1", + "ext-simplexml": "*", + "nikic/php-parser": "^4.16", + "adhocore/cli": "^v1.6", + "phpstan/phpdoc-parser": "^1.23" + }, + "require-dev": { + "nextcloud/coding-standard": "^1.1" + }, + "scripts": { + "lint": "find . -name \\*.php -not -path './tests/*' -not -path './vendor/*' -not -path './build/*' -print0 | xargs -0 -n1 php -l && php -l generate-spec && php -l merge-specs", + "cs:check": "php-cs-fixer fix --dry-run --diff", + "cs:fix": "php-cs-fixer fix", + "test:unit": "cd tests && ../generate-spec" + } } From 1cfc110d17e6c2086a21985c5eb5884a97cc16dd Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 10 Nov 2023 12:51:01 +0100 Subject: [PATCH 3/5] fix(parameters): Support int numerals and min-max lists Signed-off-by: Joas Schilling --- tests/appinfo/routes.php | 4 + tests/lib/Controller/SettingsController.php | 48 +++ tests/openapi.json | 344 ++++++++++++++++++++ 3 files changed, 396 insertions(+) diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php index bda23d9..e6e80dd 100644 --- a/tests/appinfo/routes.php +++ b/tests/appinfo/routes.php @@ -38,5 +38,9 @@ ['name' => 'Settings#defaultAndAdminScope', 'url' => '/api/{apiVersion}/default-and-admin-scope', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#nestedSchemas', 'url' => '/api/{apiVersion}/nested-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#listSchemas', 'url' => '/api/{apiVersion}/list-schemas', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#listOfIntParameters', 'url' => '/api/{apiVersion}/list-of-int', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#intParameterWithMinAndMax', 'url' => '/api/{apiVersion}/min-max', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#intParameterWithMin', 'url' => '/api/{apiVersion}/min', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#intParameterWithMax', 'url' => '/api/{apiVersion}/max', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ], ]; diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index efd8c3a..3742176 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -161,4 +161,52 @@ public function nestedSchemas(): DataResponse { public function listSchemas(): DataResponse { return new DataResponse(); } + + /** + * A route with a limited set of possible integers + * + * @param 1|2|3|4|5|6|7|8|9|10 $limit Maximum number of objects + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function listOfIntParameters(int $limit): DataResponse { + return new DataResponse(); + } + + /** + * A route with a min and max integers + * + * @param int<5, 10> $limit Between 5 and 10 + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function intParameterWithMinAndMax(int $limit): DataResponse { + return new DataResponse(); + } + + /** + * A route with a min integers + * + * @param int<5, max> $limit At least 5 + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function intParameterWithMin(int $limit): DataResponse { + return new DataResponse(); + } + + /** + * A route with a max integers + * + * @param int $limit At most 10 + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function intParameterWithMax(int $limit): DataResponse { + return new DataResponse(); + } } diff --git a/tests/openapi.json b/tests/openapi.json index f125dac..4933d18 100644 --- a/tests/openapi.json +++ b/tests/openapi.json @@ -928,6 +928,350 @@ } } } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/list-of-int": { + "post": { + "operationId": "settings-list-of-int-parameters", + "summary": "A route with a limited set of possible integers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Maximum number of objects", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "enum": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ] + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/min-max": { + "post": { + "operationId": "settings-int-parameter-with-min-and-max", + "summary": "A route with a min and max integers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Between 5 and 10", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 5, + "maximum": 10 + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/min": { + "post": { + "operationId": "settings-int-parameter-with-min", + "summary": "A route with a min integers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "At least 5", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 5 + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/max": { + "post": { + "operationId": "settings-int-parameter-with-max", + "summary": "A route with a max integers", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "At most 10", + "required": true, + "schema": { + "type": "integer", + "format": "int64", + "maximum": 10 + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } } }, "tags": [] From 1b8ed750ea4eb6156e2c6ea58cdd213bdb4db872 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 10 Nov 2023 14:37:48 +0100 Subject: [PATCH 4/5] feat(test): Add a test for mixed literals Signed-off-by: Joas Schilling --- tests/appinfo/routes.php | 1 + tests/lib/Controller/SettingsController.php | 12 +++ tests/openapi.json | 99 +++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php index e6e80dd..25abb65 100644 --- a/tests/appinfo/routes.php +++ b/tests/appinfo/routes.php @@ -42,5 +42,6 @@ ['name' => 'Settings#intParameterWithMinAndMax', 'url' => '/api/{apiVersion}/min-max', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#intParameterWithMin', 'url' => '/api/{apiVersion}/min', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#intParameterWithMax', 'url' => '/api/{apiVersion}/max', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#listOfIntStringAndBool', 'url' => '/api/{apiVersion}/mixed-list', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ], ]; diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index 3742176..3ea4047 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -209,4 +209,16 @@ public function intParameterWithMin(int $limit): DataResponse { public function intParameterWithMax(int $limit): DataResponse { return new DataResponse(); } + + /** + * A route with a list of 2 integers, 2 strings and 1 boolean + * + * @param 0|1|'yes'|'no'|true $weird Weird list + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function listOfIntStringAndBool($weird): DataResponse { + return new DataResponse(); + } } diff --git a/tests/openapi.json b/tests/openapi.json index 4933d18..9b6d173 100644 --- a/tests/openapi.json +++ b/tests/openapi.json @@ -1272,6 +1272,105 @@ } } } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/mixed-list": { + "post": { + "operationId": "settings-list-of-int-string-and-bool", + "summary": "A route with a list of 2 integers, 2 strings and 1 boolean", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "weird", + "in": "query", + "description": "Weird list", + "required": true, + "schema": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "integer", + "enum": [ + 0, + 1 + ] + }, + { + "type": "string", + "enum": [ + "yes", + "no" + ] + } + ] + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } } }, "tags": [] From 60c0b701cb3234eb328d525aa7013ad5eae4ddc9 Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 21 Dec 2023 12:02:39 +0100 Subject: [PATCH 5/5] feat(tests): Add test for "feat: Make boolean quirk an enum" Signed-off-by: Joas Schilling --- tests/appinfo/routes.php | 3 + tests/lib/Controller/SettingsController.php | 36 +++ tests/openapi.json | 255 ++++++++++++++++++++ 3 files changed, 294 insertions(+) diff --git a/tests/appinfo/routes.php b/tests/appinfo/routes.php index 25abb65..66638f0 100644 --- a/tests/appinfo/routes.php +++ b/tests/appinfo/routes.php @@ -43,5 +43,8 @@ ['name' => 'Settings#intParameterWithMin', 'url' => '/api/{apiVersion}/min', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#intParameterWithMax', 'url' => '/api/{apiVersion}/max', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ['name' => 'Settings#listOfIntStringAndBool', 'url' => '/api/{apiVersion}/mixed-list', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#booleanParameterRequired', 'url' => '/api/{apiVersion}/boolean', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#booleanParameterDefaultFalse', 'url' => '/api/{apiVersion}/boolean-false', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], + ['name' => 'Settings#booleanParameterDefaultTrue', 'url' => '/api/{apiVersion}/boolean-true', 'verb' => 'POST', 'requirements' => ['apiVersion' => '(v2)']], ], ]; diff --git a/tests/lib/Controller/SettingsController.php b/tests/lib/Controller/SettingsController.php index 3ea4047..acd82aa 100644 --- a/tests/lib/Controller/SettingsController.php +++ b/tests/lib/Controller/SettingsController.php @@ -221,4 +221,40 @@ public function intParameterWithMax(int $limit): DataResponse { public function listOfIntStringAndBool($weird): DataResponse { return new DataResponse(); } + + /** + * A route with required boolean + * + * @param bool $yesOrNo Boolean required + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function booleanParameterRequired(bool $yesOrNo): DataResponse { + return new DataResponse(); + } + + /** + * A route with boolean defaulting to false + * + * @param bool $yesOrNo Booleandefaulting to false + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function booleanParameterDefaultFalse(bool $yesOrNo = false): DataResponse { + return new DataResponse(); + } + + /** + * A route with boolean defaulting to true + * + * @param bool $yesOrNo Booleandefaulting to true + * @return DataResponse, array{}> + * + * 200: Admin settings updated + */ + public function booleanParameterDefaultTrue(bool $yesOrNo = true): DataResponse { + return new DataResponse(); + } } diff --git a/tests/openapi.json b/tests/openapi.json index 9b6d173..f0acb00 100644 --- a/tests/openapi.json +++ b/tests/openapi.json @@ -1371,6 +1371,261 @@ } } } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/boolean": { + "post": { + "operationId": "settings-boolean-parameter-required", + "summary": "A route with required boolean", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "yesOrNo", + "in": "query", + "description": "Boolean required", + "required": true, + "schema": { + "type": "integer", + "enum": [ + 0, + 1 + ] + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/boolean-false": { + "post": { + "operationId": "settings-boolean-parameter-default-false", + "summary": "A route with boolean defaulting to false", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "yesOrNo", + "in": "query", + "description": "Booleandefaulting to false", + "schema": { + "type": "integer", + "default": 0, + "enum": [ + 0, + 1 + ] + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/notifications/api/{apiVersion}/boolean-true": { + "post": { + "operationId": "settings-boolean-parameter-default-true", + "summary": "A route with boolean defaulting to true", + "description": "This endpoint requires admin access", + "tags": [ + "settings" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "yesOrNo", + "in": "query", + "description": "Booleandefaulting to true", + "schema": { + "type": "integer", + "default": 1, + "enum": [ + 0, + 1 + ] + } + }, + { + "name": "apiVersion", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "v2" + ], + "default": "v2" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Admin settings updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } } }, "tags": []