From bc6010df0f7db37334e1fc7f2f6aa75a9b5d0b13 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Wed, 4 Feb 2026 22:50:16 +0000 Subject: [PATCH 01/11] chore: Initial setup for OpenAPI 3.1 documentation Signed-off-by: matiasperrone-exo --- .env.example | 9 + .gitignore | 2 +- app/Swagger/GenericSchemas.php | 31 +++ app/Swagger/OpenApiInfo.php | 26 ++ composer.json | 4 +- composer.lock | 438 ++++++++++++++++++++++++++++++++- config/l5-swagger.php | 323 ++++++++++++++++++++++++ 7 files changed, 830 insertions(+), 3 deletions(-) create mode 100644 app/Swagger/GenericSchemas.php create mode 100644 app/Swagger/OpenApiInfo.php create mode 100644 config/l5-swagger.php diff --git a/.env.example b/.env.example index 30eb92d0..9afe5d6e 100644 --- a/.env.example +++ b/.env.example @@ -149,3 +149,12 @@ OTEL_TRACES_SAMPLER_PARENT=false # OTEL_INSTRUMENTATION_VIEW=true # OTEL_INSTRUMENTATION_LIVEWIRE=true # OTEL_INSTRUMENTATION_CONSOLE=true + +# OpenAPI CONFIG (former Swagger) + +L5_SWAGGER_CONST_HOST=${APP_URL} +L5_SWAGGER_CONST_AUTH_URL=${IDP_AUTHORIZATION_ENDPOINT} +L5_SWAGGER_CONST_TOKEN_URL=${IDP_TOKEN_ENDPOINT} +# L5_FORMAT_TO_USE_FOR_DOCS=yaml +L5_SWAGGER_GENERATE_ALWAYS=true # Dev setting +L5_SWAGGER_OPEN_API_SPEC_VERSION=3.2.0 diff --git a/.gitignore b/.gitignore index ffd7efd9..2b975b7c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ Homestead.yaml Homestead.json .env .env.* -storage/proxies +storage/* /public/assets/jquery-cookie/ /public/assets/crypto-js/ /public/assets/bootstrap-tagsinput/ diff --git a/app/Swagger/GenericSchemas.php b/app/Swagger/GenericSchemas.php new file mode 100644 index 00000000..231700fc --- /dev/null +++ b/app/Swagger/GenericSchemas.php @@ -0,0 +1,31 @@ +=5.18.3", + "symfony/yaml": "^5.0 || ^6.0 || ^7.0", + "zircote/swagger-php": "^5.0.0" + }, + "require-dev": { + "mockery/mockery": "1.*", + "orchestra/testbench": "^10.0 || ^9.0 || ^8.0 || 7.* || ^6.15 || 5.*", + "php-coveralls/php-coveralls": "^2.0", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "L5Swagger": "L5Swagger\\L5SwaggerFacade" + }, + "providers": [ + "L5Swagger\\L5SwaggerServiceProvider" + ] + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "L5Swagger\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Darius Matulionis", + "email": "darius@matulionis.lt" + } + ], + "description": "OpenApi or Swagger integration to Laravel", + "keywords": [ + "api", + "documentation", + "laravel", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/DarkaOnLine/L5-Swagger/issues", + "source": "https://github.com/DarkaOnLine/L5-Swagger/tree/9.0.1" + }, + "funding": [ + { + "url": "https://github.com/DarkaOnLine", + "type": "github" + } + ], + "time": "2025-02-28T06:25:02+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.3", @@ -550,6 +631,83 @@ }, "time": "2024-07-08T12:26:09+00:00" }, + { + "name": "doctrine/annotations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/901c2ee5d26eb64ff43c47976e114bf00843acf7", + "reference": "901c2ee5d26eb64ff43c47976e114bf00843acf7", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2 || ^3", + "ext-tokenizer": "*", + "php": "^7.2 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^2.0", + "doctrine/coding-standard": "^10", + "phpstan/phpstan": "^1.10.28", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^5.4 || ^6.4 || ^7", + "vimeo/psalm": "^4.30 || ^5.14" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/2.0.2" + }, + "abandoned": true, + "time": "2024-09-05T10:17:24+00:00" + }, { "name": "doctrine/cache", "version": "2.2.0", @@ -6488,6 +6646,53 @@ }, "time": "2024-02-26T14:37:15+00:00" }, + { + "name": "phpstan/phpdoc-parser", + "version": "2.3.2", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", + "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "doctrine/annotations": "^2.0", + "nikic/php-parser": "^5.3.0", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" + }, + "time": "2026-01-25T14:56:51+00:00" + }, { "name": "predis/predis", "version": "v2.2.2", @@ -7961,6 +8166,67 @@ ], "time": "2025-07-17T15:46:43+00:00" }, + { + "name": "swagger-api/swagger-ui", + "version": "v5.31.0", + "source": { + "type": "git", + "url": "https://github.com/swagger-api/swagger-ui.git", + "reference": "61dddd44389bf25922639afd682f50b8a0fb5cf4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/swagger-api/swagger-ui/zipball/61dddd44389bf25922639afd682f50b8a0fb5cf4", + "reference": "61dddd44389bf25922639afd682f50b8a0fb5cf4", + "shasum": "" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Anna Bodnia", + "email": "anna.bodnia@gmail.com" + }, + { + "name": "Buu Nguyen", + "email": "buunguyen@gmail.com" + }, + { + "name": "Josh Ponelat", + "email": "jponelat@gmail.com" + }, + { + "name": "Kyle Shockey", + "email": "kyleshockey1@gmail.com" + }, + { + "name": "Robert Barnwell", + "email": "robert@robertismy.name" + }, + { + "name": "Sahar Jafari", + "email": "shr.jafari@gmail.com" + } + ], + "description": " Swagger UI is a collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.", + "homepage": "http://swagger.io", + "keywords": [ + "api", + "documentation", + "openapi", + "specification", + "swagger", + "ui" + ], + "support": { + "issues": "https://github.com/swagger-api/swagger-ui/issues", + "source": "https://github.com/swagger-api/swagger-ui/tree/v5.31.0" + }, + "time": "2025-12-11T15:57:42+00:00" + }, { "name": "symfony/cache", "version": "v7.3.0", @@ -10763,6 +11029,82 @@ ], "time": "2025-05-15T09:04:05+00:00" }, + { + "name": "symfony/yaml", + "version": "v7.4.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-12-04T18:11:45+00:00" + }, { "name": "tbachert/spi", "version": "v1.0.5", @@ -11288,6 +11630,100 @@ "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, "time": "2022-06-03T18:03:27+00:00" + }, + { + "name": "zircote/swagger-php", + "version": "5.8.0", + "source": { + "type": "git", + "url": "https://github.com/zircote/swagger-php.git", + "reference": "9cf5d1a0c159894026708c9e837e69140c2d3922" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zircote/swagger-php/zipball/9cf5d1a0c159894026708c9e837e69140c2d3922", + "reference": "9cf5d1a0c159894026708c9e837e69140c2d3922", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/php-parser": "^4.19 || ^5.0", + "php": ">=7.4", + "phpstan/phpdoc-parser": "^2.0", + "psr/log": "^1.1 || ^2.0 || ^3.0", + "symfony/deprecation-contracts": "^2 || ^3", + "symfony/finder": "^5.0 || ^6.0 || ^7.0 || ^8.0", + "symfony/yaml": "^5.4 || ^6.0 || ^7.0 || ^8.0" + }, + "conflict": { + "symfony/process": ">=6, <6.4.14" + }, + "require-dev": { + "composer/package-versions-deprecated": "^1.11", + "doctrine/annotations": "^2.0", + "friendsofphp/php-cs-fixer": "^3.62.0", + "phpstan/phpstan": "^1.6 || ^2.0", + "phpunit/phpunit": "^9.0", + "rector/rector": "^1.0 || ^2.3.1", + "vimeo/psalm": "^4.30 || ^5.0" + }, + "suggest": { + "doctrine/annotations": "^2.0", + "radebatz/type-info-extras": "^1.0.2" + }, + "bin": [ + "bin/openapi" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Robert Allen", + "email": "zircote@gmail.com" + }, + { + "name": "Bob Fanger", + "email": "bfanger@gmail.com", + "homepage": "https://bfanger.nl" + }, + { + "name": "Martin Rademacher", + "email": "mano@radebatz.net", + "homepage": "https://radebatz.net" + } + ], + "description": "Generate interactive documentation for your RESTful API using PHP attributes (preferred) or PHPDoc annotations", + "homepage": "https://github.com/zircote/swagger-php", + "keywords": [ + "api", + "json", + "rest", + "service discovery" + ], + "support": { + "issues": "https://github.com/zircote/swagger-php/issues", + "source": "https://github.com/zircote/swagger-php/tree/5.8.0" + }, + "funding": [ + { + "url": "https://github.com/zircote", + "type": "github" + } + ], + "time": "2026-01-28T01:27:48+00:00" } ], "packages-dev": [ diff --git a/config/l5-swagger.php b/config/l5-swagger.php new file mode 100644 index 00000000..27d53ac2 --- /dev/null +++ b/config/l5-swagger.php @@ -0,0 +1,323 @@ + 'default', + 'enable' => true, + 'documentations' => [ + 'default' => [ + 'api' => [ + 'title' => 'Summit API Swagger UI', + ], + + 'routes' => [ + /* + * Route for accessing api documentation interface + */ + 'api' => '/api/documentation', + ], + 'paths' => [ + /* + * Edit to include full URL in ui for assets + */ + 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true), + + /* + * Edit to set path where swagger ui assets should be stored + */ + 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), + + /* + * File name of the generated json documentation file + */ + 'docs_json' => 'api-docs.json', + + /* + * File name of the generated YAML documentation file + */ + 'docs_yaml' => 'api-docs.yaml', + + /* + * Set this to `json` or `yaml` to determine which documentation file to use in UI + */ + 'format_to_use_for_docs' => env('L5_FORMAT_TO_USE_FOR_DOCS', 'json'), + + /* + * Absolute paths to directory containing the swagger annotations are stored. + */ + 'annotations' => [ + base_path('app'), + ], + ], + ], + ], + 'defaults' => [ + 'routes' => [ + /* + * Route for accessing parsed swagger annotations. + */ + 'docs' => 'docs', + + /* + * Route for Oauth2 authentication callback. + */ + 'oauth2_callback' => 'api/oauth2-callback', + + /* + * Middleware allows to prevent unexpected access to API documentation + */ + 'middleware' => [ + 'api' => [], + 'asset' => [], + 'docs' => [], + 'oauth2_callback' => [], + ], + + /* + * Route Group options + */ + 'group_options' => [], + + ], + + 'paths' => [ + /* + * Absolute path to location where parsed annotations will be stored + */ + 'docs' => storage_path('api-docs'), + + /* + * Absolute path to directory where to export views + */ + 'views' => base_path('resources/views/vendor/l5-swagger'), + + /* + * Edit to set the api's base path + */ + 'base' => env('L5_SWAGGER_BASE_PATH', null), + + /* + * Absolute path to directories that should be excluded from scanning + * @deprecated Please use `scanOptions.exclude` + * `scanOptions.exclude` overwrites this + */ + 'excludes' => [], + ], + + 'scanOptions' => [ + /** + * Configuration for default processors. Allows to pass processors configuration to swagger-php. + * + * @link https://zircote.github.io/swagger-php/reference/processors.html + */ + 'default_processors_configuration' => [ + /** Example */ + /** + * 'operationId.hash' => true, + * 'pathFilter' => [ + * 'tags' => [ + * '/pets/', + * '/store/', + * ], + * ],. + */ + ], + + /** + * analyser: defaults to \OpenApi\StaticAnalyser . + * + * @see \OpenApi\scan + */ + 'analyser' => null, + + /** + * analysis: defaults to a new \OpenApi\Analysis . + * + * @see \OpenApi\scan + */ + 'analysis' => null, + + /** + * Custom query path processors classes. + * + * @link https://github.com/zircote/swagger-php/tree/master/Examples/processors/schema-query-parameter + * @see \OpenApi\scan + */ + 'processors' => [ + // new \App\SwaggerProcessors\SchemaQueryParameter(), + ], + + /** + * pattern: string $pattern File pattern(s) to scan (default: *.php) . + * + * @see \OpenApi\scan + */ + 'pattern' => null, + + /* + * Absolute path to directories that should be excluded from scanning + * @note This option overwrites `paths.excludes` + * @see \OpenApi\scan + */ + 'exclude' => [], + + /* + * Allows to generate specs either for OpenAPI 3.0.0 or OpenAPI 3.1.0. + * By default the spec will be in version 3.0.0 + */ + 'open_api_spec_version' => env('L5_SWAGGER_OPEN_API_SPEC_VERSION', \L5Swagger\Generator::OPEN_API_DEFAULT_SPEC_VERSION), + ], + + /* + * API security definitions. Will be generated into documentation file. + */ + 'securityDefinitions' => [ + 'securitySchemes' => [ + /* + * Examples of Security schemes + */ + /* + 'api_key_security_example' => [ // Unique name of security + 'type' => 'apiKey', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for security scheme', + 'name' => 'api_key', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + 'oauth2_security_example' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'A short description for oauth2 security scheme.', + 'flow' => 'implicit', // The flow used by the OAuth2 security scheme. Valid values are "implicit", "password", "application" or "accessCode". + 'authorizationUrl' => 'http://example.com/auth', // The authorization URL to be used for (implicit/accessCode) + //'tokenUrl' => 'http://example.com/auth' // The authorization URL to be used for (password/application/accessCode) + 'scopes' => [ + 'read:projects' => 'read your projects', + 'write:projects' => 'modify projects in your account', + ] + ], + */ + + /* Open API 3.0 support + 'passport' => [ // Unique name of security + 'type' => 'oauth2', // The type of the security scheme. Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Laravel passport oauth2 security.', + 'in' => 'header', + 'scheme' => 'https', + 'flows' => [ + "password" => [ + "authorizationUrl" => config('app.url') . '/oauth/authorize', + "tokenUrl" => config('app.url') . '/oauth/token', + "refreshUrl" => config('app.url') . '/token/refresh', + "scopes" => [] + ], + ], + ], + 'sanctum' => [ // Unique name of security + 'type' => 'apiKey', // Valid values are "basic", "apiKey" or "oauth2". + 'description' => 'Enter token in format (Bearer )', + 'name' => 'Authorization', // The name of the header or query parameter to be used. + 'in' => 'header', // The location of the API key. Valid values are "query" or "header". + ], + */ + ], + 'security' => [ + /* + * Examples of Securities + */ + [ + /* + 'oauth2_security_example' => [ + 'read', + 'write' + ], + + 'passport' => [] + */ + ], + ], + ], + + /* + * Set this to `true` in development mode so that docs would be regenerated on each request + * Set this to `false` to disable swagger generation on production + */ + 'generate_always' => env('L5_SWAGGER_GENERATE_ALWAYS', true), + + /* + * Set this to `true` to generate a copy of documentation in yaml format + */ + 'generate_yaml_copy' => env('L5_SWAGGER_GENERATE_YAML_COPY', false), + + /* + * Edit to trust the proxy's ip address - needed for AWS Load Balancer + * string[] + */ + 'proxy' => false, + + /* + * Configs plugin allows to fetch external configs instead of passing them to SwaggerUIBundle. + * See more at: https://github.com/swagger-api/swagger-ui#configs-plugin + */ + 'additional_config_url' => null, + + /* + * Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), + * 'method' (sort by HTTP method). + * Default is the order returned by the server unchanged. + */ + 'operations_sort' => env('L5_SWAGGER_OPERATIONS_SORT', null), + + /* + * Pass the validatorUrl parameter to SwaggerUi init on the JS side. + * A null value here disables validation. + */ + 'validator_url' => null, + + /* + * Swagger UI configuration parameters + */ + 'ui' => [ + 'display' => [ + 'dark_mode' => env('L5_SWAGGER_UI_DARK_MODE', false), + /* + * Controls the default expansion setting for the operations and tags. It can be : + * 'list' (expands only the tags), + * 'full' (expands the tags and operations), + * 'none' (expands nothing). + */ + 'doc_expansion' => env('L5_SWAGGER_UI_DOC_EXPANSION', 'none'), + + /** + * If set, enables filtering. The top bar will show an edit box that + * you can use to filter the tagged operations that are shown. Can be + * Boolean to enable or disable, or a string, in which case filtering + * will be enabled using that string as the filter expression. Filtering + * is case-sensitive matching the filter expression anywhere inside + * the tag. + */ + 'filter' => env('L5_SWAGGER_UI_FILTERS', true), // true | false + ], + + 'authorization' => [ + /* + * If set to true, it persists authorization data, and it would not be lost on browser close/refresh + */ + 'persist_authorization' => env('L5_SWAGGER_UI_PERSIST_AUTHORIZATION', false), + + 'oauth2' => [ + /* + * If set to true, adds PKCE to AuthorizationCodeGrant flow + */ + 'use_pkce_with_authorization_code_grant' => false, + ], + ], + ], + /* + * Constants which can be used in annotations + */ + 'constants' => [ + 'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://localhost'), + 'L5_SWAGGER_CONST_AUTH_URL' => env('L5_SWAGGER_CONST_AUTH_URL', 'http://localhost/oauth/authorize'), + 'L5_SWAGGER_CONST_TOKEN_URL' => env('L5_SWAGGER_CONST_TOKEN_URL', 'http://localhost/oauth/token'), + + ], + ], +]; From 6adfbfc224cc04c69d396ff025f40e89a5a2b442 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 5 Feb 2026 19:40:45 +0000 Subject: [PATCH 02/11] chore: Move to OpenAPI v3.1.2 so UI supports it Signed-off-by: matiasperrone-exo --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 9afe5d6e..c2886741 100644 --- a/.env.example +++ b/.env.example @@ -157,4 +157,4 @@ L5_SWAGGER_CONST_AUTH_URL=${IDP_AUTHORIZATION_ENDPOINT} L5_SWAGGER_CONST_TOKEN_URL=${IDP_TOKEN_ENDPOINT} # L5_FORMAT_TO_USE_FOR_DOCS=yaml L5_SWAGGER_GENERATE_ALWAYS=true # Dev setting -L5_SWAGGER_OPEN_API_SPEC_VERSION=3.2.0 +L5_SWAGGER_OPEN_API_SPEC_VERSION=3.1.2 From e89e6ebe36edb007be08804eb82e8c079bd32b8a Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 5 Feb 2026 20:10:24 +0000 Subject: [PATCH 03/11] chore: Add Basic schema which will be referenced by all the other Models schemas Signed-off-by: matiasperrone-exo --- app/Swagger/GenericSchemas.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/Swagger/GenericSchemas.php b/app/Swagger/GenericSchemas.php index 231700fc..ee8f0b2d 100644 --- a/app/Swagger/GenericSchemas.php +++ b/app/Swagger/GenericSchemas.php @@ -28,4 +28,18 @@ class BearerAuthSchema )] class PaginateDataSchemaResponseSchema { +} + +#[OA\Schema( + schema: 'BaseSerializerSchema', + type: 'object', + properties: [ + new OA\Property(property: 'id', type: 'integer', description: 'Unique identifier', example: 1), + new OA\Property(property: 'created_at', type: 'integer', description: 'Creation timestamp (epoch)', example: 1609459200), + new OA\Property(property: 'updated_at', type: 'integer', description: 'Last update timestamp (epoch)', example: 1609459200), + ], + description: 'Base serializer fields' +)] +class BaseSerializerSchema +{ } \ No newline at end of file From 4214f1bc4912db0dc992cd4644d3f9a3c05e1df5 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 5 Feb 2026 20:34:06 +0000 Subject: [PATCH 04/11] chore: change name for Base schema Signed-off-by: matiasperrone-exo --- app/Swagger/GenericSchemas.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Swagger/GenericSchemas.php b/app/Swagger/GenericSchemas.php index ee8f0b2d..df4432c4 100644 --- a/app/Swagger/GenericSchemas.php +++ b/app/Swagger/GenericSchemas.php @@ -31,7 +31,7 @@ class PaginateDataSchemaResponseSchema } #[OA\Schema( - schema: 'BaseSerializerSchema', + schema: 'Base', type: 'object', properties: [ new OA\Property(property: 'id', type: 'integer', description: 'Unique identifier', example: 1), @@ -40,6 +40,6 @@ class PaginateDataSchemaResponseSchema ], description: 'Base serializer fields' )] -class BaseSerializerSchema +class BaseSchema { } \ No newline at end of file From 7c0a67bb01a99b3686265769b4ac4fa610e83eca Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 5 Feb 2026 21:02:18 +0000 Subject: [PATCH 05/11] chore: Add requested changes Signed-off-by: matiasperrone-exo --- app/Swagger/OpenApiInfo.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Swagger/OpenApiInfo.php b/app/Swagger/OpenApiInfo.php index ad0fb16b..8e627c47 100644 --- a/app/Swagger/OpenApiInfo.php +++ b/app/Swagger/OpenApiInfo.php @@ -13,12 +13,12 @@ email: "support@openstack.org" ), license: new OA\License( - name: "MIT", - url: "https://opensource.org/licenses/MIT" + name: "Apache 2.0", + url: "http://www.apache.org/licenses/LICENSE-2.0" ) )] #[OA\Server( - url: "/", + url: L5_SWAGGER_CONST_HOST, description: "IDP API Server" )] class OpenApiInfo From dbc1af1d92d3ebd8600eae46287580a9789c7b6e Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Wed, 11 Feb 2026 21:26:33 +0000 Subject: [PATCH 06/11] chore: remove unneeded schema Signed-off-by: matiasperrone-exo --- app/Swagger/GenericSchemas.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/Swagger/GenericSchemas.php b/app/Swagger/GenericSchemas.php index df4432c4..b0cbd1b8 100644 --- a/app/Swagger/GenericSchemas.php +++ b/app/Swagger/GenericSchemas.php @@ -5,16 +5,6 @@ use OpenApi\Attributes as OA; -#[OA\SecurityScheme( - securityScheme: "bearerAuth", - type: "http", - scheme: "bearer", - bearerFormat: "JWT" -)] -class BearerAuthSchema -{ -} - #[OA\Schema( schema: 'PaginateDataSchemaResponse', type: 'object', From 20eed023f7b2094c16ba03a4cf45ef5bc7562395 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Wed, 11 Feb 2026 22:42:10 +0000 Subject: [PATCH 07/11] update .env.example with right values for OpenAPI docs Signed-off-by: matiasperrone-exo --- .env.example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index c2886741..0e19658e 100644 --- a/.env.example +++ b/.env.example @@ -153,8 +153,8 @@ OTEL_TRACES_SAMPLER_PARENT=false # OpenAPI CONFIG (former Swagger) L5_SWAGGER_CONST_HOST=${APP_URL} -L5_SWAGGER_CONST_AUTH_URL=${IDP_AUTHORIZATION_ENDPOINT} -L5_SWAGGER_CONST_TOKEN_URL=${IDP_TOKEN_ENDPOINT} +L5_SWAGGER_CONST_AUTH_URL='/oauth2/auth' +L5_SWAGGER_CONST_TOKEN_URL='/oauth2/token' # L5_FORMAT_TO_USE_FOR_DOCS=yaml L5_SWAGGER_GENERATE_ALWAYS=true # Dev setting L5_SWAGGER_OPEN_API_SPEC_VERSION=3.1.2 From a2595292ff3012208000bda64b52177b2ca2f141 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 12 Feb 2026 19:14:00 +0000 Subject: [PATCH 08/11] chore: change API name in config Signed-off-by: matiasperrone-exo --- config/l5-swagger.php | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/config/l5-swagger.php b/config/l5-swagger.php index 27d53ac2..6cf40432 100644 --- a/config/l5-swagger.php +++ b/config/l5-swagger.php @@ -6,7 +6,7 @@ 'documentations' => [ 'default' => [ 'api' => [ - 'title' => 'Summit API Swagger UI', + 'title' => 'OpenStackID API Swagger UI', ], 'routes' => [ @@ -22,8 +22,8 @@ 'use_absolute_path' => env('L5_SWAGGER_USE_ABSOLUTE_PATH', true), /* - * Edit to set path where swagger ui assets should be stored - */ + * Edit to set path where swagger ui assets should be stored + */ 'swagger_ui_assets_path' => env('L5_SWAGGER_UI_ASSETS_PATH', 'vendor/swagger-api/swagger-ui/dist/'), /* @@ -110,16 +110,16 @@ * @link https://zircote.github.io/swagger-php/reference/processors.html */ 'default_processors_configuration' => [ - /** Example */ - /** - * 'operationId.hash' => true, - * 'pathFilter' => [ - * 'tags' => [ - * '/pets/', - * '/store/', - * ], - * ],. - */ + /** Example */ + /** + * 'operationId.hash' => true, + * 'pathFilter' => [ + * 'tags' => [ + * '/pets/', + * '/store/', + * ], + * ],. + */ ], /** @@ -169,7 +169,7 @@ /* * API security definitions. Will be generated into documentation file. - */ + */ 'securityDefinitions' => [ 'securitySchemes' => [ /* @@ -315,9 +315,9 @@ */ 'constants' => [ 'L5_SWAGGER_CONST_HOST' => env('L5_SWAGGER_CONST_HOST', 'http://localhost'), - 'L5_SWAGGER_CONST_AUTH_URL' => env('L5_SWAGGER_CONST_AUTH_URL', 'http://localhost/oauth/authorize'), - 'L5_SWAGGER_CONST_TOKEN_URL' => env('L5_SWAGGER_CONST_TOKEN_URL', 'http://localhost/oauth/token'), + 'L5_SWAGGER_CONST_AUTH_URL' => env('L5_SWAGGER_CONST_AUTH_URL', 'http://localhost/oauth/authorize'), + 'L5_SWAGGER_CONST_TOKEN_URL' => env('L5_SWAGGER_CONST_TOKEN_URL', 'http://localhost/oauth/token'), ], ], -]; +]; \ No newline at end of file From 1e37e840047951abef06f2455e54d8731a1f5920 Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Wed, 11 Feb 2026 22:38:14 +0000 Subject: [PATCH 09/11] feat: Add OpenAPI documentation on controller OAuth2UserApiController v2 routes Signed-off-by: matiasperrone-exo --- .../Api/OAuth2/OAuth2UserApiController.php | 45 ++++++ app/Swagger/Models/BaseUserSchema.php | 26 ++++ app/Swagger/Models/GroupSchema.php | 27 ++++ app/Swagger/Models/UserSchema.php | 67 ++++++++ .../OAuth2UserApiControllerSchemas.php | 144 ++++++++++++++++++ app/Swagger/Security/UsersOAuth2Schema.php | 26 ++++ 6 files changed, 335 insertions(+) create mode 100644 app/Swagger/Models/BaseUserSchema.php create mode 100644 app/Swagger/Models/GroupSchema.php create mode 100644 app/Swagger/Models/UserSchema.php create mode 100644 app/Swagger/OAuth2UserApiControllerSchemas.php create mode 100644 app/Swagger/Security/UsersOAuth2Schema.php diff --git a/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php index fd0b744f..71bb897c 100644 --- a/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php +++ b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php @@ -37,8 +37,11 @@ use OAuth2\ResourceServer\IUserService; use Utils\Http\HttpContentType; use Utils\Services\ILogService; +use App\libs\OAuth2\IUserScopes; use Exception; +use OpenApi\Attributes as OA; use OpenId\Services\IUserService as IOpenIdUserService; +use Symfony\Component\HttpFoundation\Response as HttpResponse; /** * Class OAuth2UserApiController * @package App\Http\Controllers\Api\OAuth2 @@ -336,6 +339,48 @@ public function get($id) * @param $id * @return \Illuminate\Http\JsonResponse|mixed */ + #[OA\Get( + path: '/api/v2/users/{id}', + summary: 'Get a user by ID', + operationId: 'getUserByIdV2', + tags: ['Users'], + security: [ + ['user_oauth2' => [ + IUserScopes::ReadAll, + ]], + ], + parameters: [ + new OA\Parameter( + name: 'id', + description: 'User ID', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer') + ), + new OA\Parameter( + name: 'expand', + description: 'Expand relations: groups', + in: 'query', + required: false, + schema: new OA\Schema(type: 'string') + ), + ], + responses: [ + new OA\Response( + response: HttpResponse::HTTP_OK, + description: 'OK', + content: new OA\JsonContent(ref: '#/components/schemas/User') + ), + new OA\Response( + response: HttpResponse::HTTP_NOT_FOUND, + description: 'Not Found' + ), + new OA\Response( + response: HttpResponse::HTTP_INTERNAL_SERVER_ERROR, + description: 'Server Error' + ), + ] + )] public function getV2($id) { return $this->processRequest(function() use($id) { diff --git a/app/Swagger/Models/BaseUserSchema.php b/app/Swagger/Models/BaseUserSchema.php new file mode 100644 index 00000000..3122e1e2 --- /dev/null +++ b/app/Swagger/Models/BaseUserSchema.php @@ -0,0 +1,26 @@ + 'Read All Users Data', + ], + ), + ], + ) +] +class UsersOAuth2Schema +{ +} From a4e9256d843d92795e78c694d4190f15da700dbd Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 12 Feb 2026 19:11:26 +0000 Subject: [PATCH 10/11] fix: Update OAuth2UserApiController security scheme to use constants for URLs Signed-off-by: matiasperrone-exo --- app/Swagger/Security/UsersOAuth2Schema.php | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/Swagger/Security/UsersOAuth2Schema.php b/app/Swagger/Security/UsersOAuth2Schema.php index 6ae60f32..ad956645 100644 --- a/app/Swagger/Security/UsersOAuth2Schema.php +++ b/app/Swagger/Security/UsersOAuth2Schema.php @@ -7,20 +7,20 @@ #[ OA\SecurityScheme( - type: 'oauth2', - securityScheme: 'user_oauth2', - flows: [ - new OA\Flow( - flow: 'authorizationCode', - authorizationUrl: '/oauth2/auth', - tokenUrl: '/oauth2/token', - scopes: [ - IUserScopes::ReadAll => 'Read All Users Data', - ], - ), - ], - ) + type: 'oauth2', + securityScheme: 'user_oauth2', + flows: [ + new OA\Flow( + flow: 'authorizationCode', + authorizationUrl: L5_SWAGGER_CONST_AUTH_URL, + tokenUrl: L5_SWAGGER_CONST_TOKEN_URL, + scopes: [ + IUserScopes::ReadAll => 'Read All Users Data', + ], + ), + ], +) ] class UsersOAuth2Schema { -} +} \ No newline at end of file From 429d85e9c39fd4b546fe12087543cf58398ec9fd Mon Sep 17 00:00:00 2001 From: matiasperrone-exo Date: Thu, 12 Feb 2026 19:58:35 +0000 Subject: [PATCH 11/11] chore: add legeed "(only for service accounts)" Signed-off-by: matiasperrone-exo --- app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php index 71bb897c..7ae643f8 100644 --- a/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php +++ b/app/Http/Controllers/Api/OAuth2/OAuth2UserApiController.php @@ -341,7 +341,7 @@ public function get($id) */ #[OA\Get( path: '/api/v2/users/{id}', - summary: 'Get a user by ID', + summary: 'Get a user by ID (only for "SERVICE" accounts type)', operationId: 'getUserByIdV2', tags: ['Users'], security: [