From f78b9a8c3e0ebb6cd806c436cbab5f0ca564d832 Mon Sep 17 00:00:00 2001 From: "LDFOUR\\luisd" Date: Fri, 28 Mar 2025 15:49:54 -0300 Subject: [PATCH 1/3] WN-280 Refactored Swagger documentation for API key authentication - Removed Basic Auth from Swagger security schemes and endpoint annotations - Updated all public endpoints to use API Key authentication only - Added "(public)" to the summary of API key-accessible endpoints - Marked obsolete endpoints as deprecated and hid them via CSS (still visible in docs) - Added a visual note at the top of the Swagger UI explaining authentication requirements --- .../Controllers/ApplicationController.php | 10 ++ app/Http/Controllers/FileUploadController.php | 2 + .../Controllers/OrganisationController.php | 6 +- app/Http/Controllers/RegionController.php | 12 ++ app/Http/Controllers/UsageLogController.php | 8 ++ app/Http/Controllers/WhatNowController.php | 54 +++++--- config/l5-swagger.php | 94 +++----------- .../views/vendor/l5-swagger/index.blade.php | 53 ++++++++ storage/api-docs/api-docs.json | 116 +++++++++++++----- 9 files changed, 226 insertions(+), 129 deletions(-) diff --git a/app/Http/Controllers/ApplicationController.php b/app/Http/Controllers/ApplicationController.php index 573c448..64f4fa9 100644 --- a/app/Http/Controllers/ApplicationController.php +++ b/app/Http/Controllers/ApplicationController.php @@ -66,6 +66,8 @@ public function __construct( * tags={"Applications"}, * summary="Get all applications for a user", * operationId="getAllForUser", + * security={}, + * deprecated=true, * @OA\Parameter( * name="userId", * in="query", @@ -121,6 +123,8 @@ public function getAllForUser(Request $request) * tags={"Applications"}, * summary="Get an application by ID", * operationId="getApplicationById", + * security={}, + * deprecated=true, * @OA\Parameter( * name="id", * in="path", @@ -177,6 +181,8 @@ public function getById($id) * tags={"Applications"}, * summary="Create a new application", * operationId="createApplication", + * security={}, + * deprecated=true, * @OA\RequestBody( * required=true, * @OA\JsonContent( @@ -236,6 +242,8 @@ public function create(Request $request) * tags={"Applications"}, * summary="Update an application by ID", * operationId="updateApplication", + * security={}, + * deprecated=true, * @OA\Parameter( * name="id", * in="path", @@ -294,6 +302,8 @@ public function update(Request $request, $id) * tags={"Applications"}, * summary="Delete an application by ID", * operationId="deleteApplication", + * security={}, + * deprecated=true, * @OA\Parameter( * name="id", * in="path", diff --git a/app/Http/Controllers/FileUploadController.php b/app/Http/Controllers/FileUploadController.php index 0766255..ab3564e 100644 --- a/app/Http/Controllers/FileUploadController.php +++ b/app/Http/Controllers/FileUploadController.php @@ -19,6 +19,8 @@ class FileUploadController extends Controller * tags={"Whatnow"}, * summary="Upload a file", * operationId="uploadFile", + * security={}, + * deprecated=true, * @OA\RequestBody( * required=true, * @OA\MediaType( diff --git a/app/Http/Controllers/OrganisationController.php b/app/Http/Controllers/OrganisationController.php index 1b899ea..4e41198 100644 --- a/app/Http/Controllers/OrganisationController.php +++ b/app/Http/Controllers/OrganisationController.php @@ -51,7 +51,7 @@ public function __construct( /** * @OA\Get( * path="/org", - * summary="Get all organisations", + * summary="Get all organisations (public)", * security={{"ApiKeyAuth": {}}}, * tags={"Organisation"}, * @OA\Response( @@ -99,7 +99,7 @@ public function getAll(Request $request) /** * @OA\Get( * path="/org/{code}", - * summary="Get organisation by country code", + * summary="Get organisation by country code (public)", * tags={"Organisation"}, * security={{"ApiKeyAuth": {}}}, * @OA\Parameter( @@ -152,6 +152,8 @@ public function getById($code, Request $request) * path="/org/{code}", * tags={"Organisation"}, * summary="Update an organisation by its country code", + * security={}, + * deprecated=true, * description="Updates the details of an organisation based on the provided country code.", * operationId="OrganisationController@putById", * @OA\Parameter( diff --git a/app/Http/Controllers/RegionController.php b/app/Http/Controllers/RegionController.php index 997d9f2..cee8373 100644 --- a/app/Http/Controllers/RegionController.php +++ b/app/Http/Controllers/RegionController.php @@ -43,6 +43,8 @@ public function __construct( * tags={"Regions"}, * summary="Create a new region", * operationId="createRegion", + * security={}, + * deprecated=true, * @OA\RequestBody( * required=true, * @OA\JsonContent( @@ -132,6 +134,8 @@ public function createRegion(Request $request) * tags={"Regions"}, * summary="Update an existing region", * operationId="updateRegion", + * security={}, + * deprecated=true, * @OA\Parameter( * name="regionId", * in="path", @@ -219,6 +223,8 @@ public function updateRegion(Request $request, $regionId) * path="/regions/{country_code}", * summary="Get all regions for a specific organisation by country code", * tags={"Regions"}, + * security={}, + * deprecated=true, * @OA\Parameter( * name="country_code", * in="path", @@ -273,6 +279,8 @@ public function getAllForOrganisation($country_code) * path="/regions/{country_code}/{code}", * summary="Get regions for a specific organisation by country code and language code", * tags={"Regions"}, + * security={}, + * deprecated=true, * @OA\Parameter( * name="country_code", * in="path", @@ -333,6 +341,8 @@ public function getForCountryCode($country_code, $code) * tags={"Regions"}, * summary="Delete a region", * operationId="deleteRegion", + * security={}, + * deprecated=true, * @OA\Parameter( * name="regionId", * in="path", @@ -372,6 +382,8 @@ public function deleteRegion($regionId) * tags={"Regions"}, * summary="Delete a region translation", * operationId="deleteTranslation", + * security={}, + * deprecated=true, * @OA\Parameter( * name="translationId", * in="path", diff --git a/app/Http/Controllers/UsageLogController.php b/app/Http/Controllers/UsageLogController.php index 2c32ead..08666a1 100644 --- a/app/Http/Controllers/UsageLogController.php +++ b/app/Http/Controllers/UsageLogController.php @@ -52,6 +52,8 @@ public function __construct(ApplicationRepositoryInterface $applicationRepo, Usa * tags={"UsageLogs"}, * summary="Get application usage logs", * operationId="getApplicationLogs", + * security={}, + * deprecated=true, * @OA\Parameter( * name="fromDate", * in="query", @@ -126,6 +128,8 @@ public function getApplicationLogs(Request $request) * tags={"UsageLogs"}, * summary="Get endpoint usage logs", * operationId="getEndpointLogs", + * security={}, + * deprecated=true, * @OA\Parameter( * name="fromDate", * in="query", @@ -198,6 +202,8 @@ public function getEndpointLogs(Request $request) * tags={"UsageLogs"}, * summary="Export usage logs as CSV", * operationId="exportUsageLogs", + * security={}, + * deprecated=true, * @OA\Parameter( * name="fromDate", * in="query", @@ -306,6 +312,8 @@ public function getForApplication(int $applicationId) * tags={"UsageLogs"}, * summary="Get usage log totals", * operationId="getTotals", + * security={}, + * deprecated=true, * @OA\Parameter( * name="society", * in="query", diff --git a/app/Http/Controllers/WhatNowController.php b/app/Http/Controllers/WhatNowController.php index 3e3a0b9..9ef0c21 100644 --- a/app/Http/Controllers/WhatNowController.php +++ b/app/Http/Controllers/WhatNowController.php @@ -93,7 +93,7 @@ public function __construct( * @OA\Get( * path="/whatnow/{id}", * tags={"Whatnow"}, - * summary="Obtiene un recurso publicado por ID", + * summary="Obtiene un recurso publicado por ID (public)", * description="Retorna los detalles de un recurso publicado basado en el ID proporcionado.", * operationId="getPublishedById", * security={{"ApiKeyAuth": {}}}, @@ -159,6 +159,8 @@ public function getPublishedById($id) * tags={"Whatnow"}, * summary="Get the latest revision of a WhatNow entity by ID", * operationId="getLatestById", + * security={}, + * deprecated=true, * @OA\Parameter( * name="id", * in="path", @@ -214,6 +216,8 @@ public function getLatestById($id) * tags={"Whatnow"}, * summary="Delete a WhatNow entity by ID", * operationId="deleteById", + * security={}, + * deprecated=true, * @OA\Parameter( * name="id", * in="path", @@ -260,7 +264,7 @@ public function deleteById($id) * @OA\Get( * path="/org/{code}/whatnow", * tags={"Whatnow"}, - * summary="Get a feed of WhatNow entities for a specific organisation", + * summary="Get a feed of WhatNow entities for a specific organisation (public)", * operationId="getFeed", * security={{"ApiKeyAuth": {}}}, * @OA\Parameter( @@ -364,6 +368,8 @@ protected function changeLogStatus($status){ * tags={"Whatnow"}, * summary="Get the latest revisions for a country code", * operationId="getLatestForCountryCode", + * security={}, + * deprecated=true, * @OA\Parameter( * name="code", * in="path", @@ -416,6 +422,8 @@ public function getLatestForCountryCode($code) * tags={"Whatnow"}, * summary="Get the latest revisions for a specific region", * operationId="getLatestForRegion", + * security={}, + * deprecated=true, * @OA\Parameter( * name="code", * in="path", @@ -501,6 +509,8 @@ public function getAllRevisions() * tags={"Whatnow"}, * summary="Create a new WhatNow entity", * operationId="createWhatNowEntity", + * security={}, + * deprecated=true, * @OA\RequestBody( * required=true, * @OA\JsonContent( @@ -629,6 +639,8 @@ public function post() * tags={"Whatnow"}, * summary="Update a WhatNow entity by ID", * operationId="putById", + * deprecated=true, + * security={}, * @OA\Parameter( * name="id", * in="path", @@ -678,22 +690,22 @@ public function putById($id) ]); } - try { - $this->validate($this->request, [ - 'countryCode' => 'alpha|size:3', - 'eventType' => 'string|max:50', - 'regionName' => 'nullable|string', - 'translations' => 'array', - 'translations.*.webUrl' => 'nullable|string', - 'translations.*.lang' => 'alpha|size:2', - 'translations.*.title' => 'string', - 'translations.*.description' => 'string', - ]); - } catch (ValidationException $e) { - Log::info($e->getMessage()); - - return $e->getResponse(); - } + // try { + // $this->validate($this->request, [ + // 'countryCode' => 'alpha|size:3', + // 'eventType' => 'string|max:50', + // 'regionName' => 'nullable|string', + // 'translations' => 'array', + // 'translations.*.webUrl' => 'nullable|string', + // 'translations.*.lang' => 'alpha|size:2', + // 'translations.*.title' => 'string', + // 'translations.*.description' => 'string', + // ]); + // } catch (ValidationException $e) { + // Log::info($e->getMessage()); + + // return $e->getResponse(); + // } try { $org = $this->orgRepo->findByCountryCode($this->request->input('countryCode')); @@ -755,6 +767,8 @@ public function putById($id) * tags={"Whatnow"}, * summary="Create a new translation for a WhatNow entity", * operationId="createNewTranslation", + * deprecated=true, + * security={}, * @OA\Parameter( * name="id", * in="path", @@ -844,6 +858,8 @@ public function createNewTranslation($id) * tags={"Whatnow"}, * summary="Update the published status of a translation", * operationId="patchTranslation", + * deprecated=true, + * security={}, * @OA\Parameter( * name="id", * in="path", @@ -927,6 +943,8 @@ public function patchTranslation($id, $translationId) * tags={"Whatnow"}, * summary="Publish translations by IDs", * operationId="publishTranslationsByIds", + * deprecated=true, + * security={}, * @OA\RequestBody( * required=true, * @OA\JsonContent( diff --git a/config/l5-swagger.php b/config/l5-swagger.php index 0625e03..7715ef0 100644 --- a/config/l5-swagger.php +++ b/config/l5-swagger.php @@ -48,6 +48,21 @@ ], ], ], + 'users' => [ + 'api' => [ + 'title' => 'API Usuarios Autenticados', + ], + 'routes' => [ + 'api' => 'api/users/documentation', + ], + 'paths' => [ + 'docs_json' => 'users-docs.json', + 'docs_yaml' => 'users-docs.yaml', + 'annotations' => [ + base_path('app/Http/Controllers/ApiUsers'), + ], + ], + ], ], 'defaults' => [ 'routes' => [ @@ -75,7 +90,6 @@ * Route Group options */ 'group_options' => [], - 'security' => [['BasicAuth' => []]], ], 'paths' => [ @@ -109,8 +123,8 @@ * @link https://zircote.github.io/swagger-php/reference/processors.html */ 'default_processors_configuration' => [ - /** Example */ - /** + /** Example */ + /** * 'operationId.hash' => true, * 'pathFilter' => [ * 'tags' => [ @@ -170,78 +184,8 @@ * 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". - ], - */ - 'BasicAuth' => [ - 'type' => 'http', - 'scheme' => 'basic' - ], - 'ApiKeyAuth' => [ - 'type' => 'apiKey', - 'in' => 'header', - 'name' => 'x-api-key', - ], - ], - 'security' => [ - /* - * Examples of Securities - */ - [ - /* - 'oauth2_security_example' => [ - 'read', - 'write' - ], - - 'passport' => [] - */ - 'BasicAuth' => [] - ], - ], + 'securitySchemes' => [], + 'security' => [], ], /* diff --git a/resources/views/vendor/l5-swagger/index.blade.php b/resources/views/vendor/l5-swagger/index.blade.php index 7d346a7..4e136a6 100644 --- a/resources/views/vendor/l5-swagger/index.blade.php +++ b/resources/views/vendor/l5-swagger/index.blade.php @@ -114,6 +114,42 @@ } @endif + @@ -131,6 +167,23 @@ configUrl: {!! isset($configUrl) ? '"' . $configUrl . '"' : 'null' !!}, validatorUrl: {!! isset($validatorUrl) ? '"' . $validatorUrl . '"' : 'null' !!}, oauth2RedirectUrl: "{{ route('l5-swagger.'.$documentation.'.oauth2_callback', [], $useAbsolutePath) }}", + supportedSubmitMethods: ['get'], + onComplete: function () { + // Crear el mensaje + const notice = document.createElement('div'); + notice.innerHTML = ` +
+ 🔐 Note: Only endpoints tagged as Public are available for testing in Swagger UI. + These require an API Key (X-API-KEY) passed in the request header. +
+ `; + + // Insertarlo arriba del contenido + const topBar = document.querySelector('.swagger-ui .info'); + if (topBar && topBar.parentNode) { + topBar.parentNode.insertBefore(notice, topBar.nextSibling); + } + }, requestInterceptor: function(request) { request.headers['X-CSRF-TOKEN'] = '{{ csrf_token() }}'; diff --git a/storage/api-docs/api-docs.json b/storage/api-docs/api-docs.json index dc16378..a1e4b0d 100644 --- a/storage/api-docs/api-docs.json +++ b/storage/api-docs/api-docs.json @@ -49,7 +49,9 @@ } } } - } + }, + "deprecated": true, + "security": [] }, "post": { "tags": [ @@ -112,7 +114,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/apps/{id}": { @@ -153,7 +157,9 @@ } } } - } + }, + "deprecated": true, + "security": [] }, "delete": { "tags": [ @@ -192,7 +198,9 @@ } } } - } + }, + "deprecated": true, + "security": [] }, "patch": { "tags": [ @@ -248,7 +256,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/upload": { @@ -297,7 +307,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/org": { @@ -305,7 +317,7 @@ "tags": [ "Organisation" ], - "summary": "Get all organisations", + "summary": "Get all organisations (public)", "operationId": "04f86edf4b63c5b0f297e462633924b4", "responses": { "200": { @@ -339,7 +351,7 @@ "tags": [ "Organisation" ], - "summary": "Get organisation by country code", + "summary": "Get organisation by country code (public)", "operationId": "b4a9c9d91b102ab0d0709eae9104db61", "parameters": [ { @@ -477,7 +489,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/regions": { @@ -566,7 +580,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/regions/region/{regionId}": { @@ -658,7 +674,9 @@ } } } - } + }, + "deprecated": true, + "security": [] }, "delete": { "tags": [ @@ -697,7 +715,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/regions/{country_code}": { @@ -734,7 +754,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/regions/{country_code}/{code}": { @@ -783,7 +805,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/regions/region/translation/{translationId}": { @@ -824,7 +848,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/usage/applications": { @@ -875,7 +901,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/usage/endpoints": { @@ -926,7 +954,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/usage/export": { @@ -977,7 +1007,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/usage/totals": { @@ -1054,7 +1086,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow/{id}": { @@ -1062,7 +1096,7 @@ "tags": [ "Whatnow" ], - "summary": "Obtiene un recurso publicado por ID", + "summary": "Obtiene un recurso publicado por ID (public)", "description": "Retorna los detalles de un recurso publicado basado en el ID proporcionado.", "operationId": "getPublishedById", "parameters": [ @@ -1200,7 +1234,9 @@ } } } - } + }, + "deprecated": true, + "security": [] }, "delete": { "tags": [ @@ -1239,7 +1275,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow/{id}/revisions/latest": { @@ -1280,7 +1318,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/org/{code}/whatnow": { @@ -1288,7 +1328,7 @@ "tags": [ "Whatnow" ], - "summary": "Get a feed of WhatNow entities for a specific organisation", + "summary": "Get a feed of WhatNow entities for a specific organisation (public)", "operationId": "getFeed", "parameters": [ { @@ -1392,7 +1432,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/org/{code}/{region}/whatnow/revisions/latest": { @@ -1441,7 +1483,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow": { @@ -1531,7 +1575,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow/{id}/revisions": { @@ -1618,7 +1664,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow/{id}/revisions/{translationId}": { @@ -1689,7 +1737,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } }, "/whatnow/publish": { @@ -1741,7 +1791,9 @@ } } } - } + }, + "deprecated": true, + "security": [] } } }, @@ -1769,10 +1821,6 @@ ], "components": { "securitySchemes": { - "BasicAuth": { - "type": "http", - "scheme": "basic" - }, "ApiKeyAuth": { "type": "apiKey", "in": "header", From 22dbee818909b3da8ce2d5349122013cfb12d1e2 Mon Sep 17 00:00:00 2001 From: "LDFOUR\\luisd" Date: Fri, 28 Mar 2025 15:54:08 -0300 Subject: [PATCH 2/3] rollback change --- app/Http/Controllers/WhatNowController.php | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/WhatNowController.php b/app/Http/Controllers/WhatNowController.php index 9ef0c21..2b32426 100644 --- a/app/Http/Controllers/WhatNowController.php +++ b/app/Http/Controllers/WhatNowController.php @@ -690,22 +690,22 @@ public function putById($id) ]); } - // try { - // $this->validate($this->request, [ - // 'countryCode' => 'alpha|size:3', - // 'eventType' => 'string|max:50', - // 'regionName' => 'nullable|string', - // 'translations' => 'array', - // 'translations.*.webUrl' => 'nullable|string', - // 'translations.*.lang' => 'alpha|size:2', - // 'translations.*.title' => 'string', - // 'translations.*.description' => 'string', - // ]); - // } catch (ValidationException $e) { - // Log::info($e->getMessage()); - - // return $e->getResponse(); - // } + try { + $this->validate($this->request, [ + 'countryCode' => 'alpha|size:3', + 'eventType' => 'string|max:50', + 'regionName' => 'nullable|string', + 'translations' => 'array', + 'translations.*.webUrl' => 'nullable|string', + 'translations.*.lang' => 'alpha|size:2', + 'translations.*.title' => 'string', + 'translations.*.description' => 'string', + ]); + } catch (ValidationException $e) { + Log::info($e->getMessage()); + + return $e->getResponse(); + } try { $org = $this->orgRepo->findByCountryCode($this->request->input('countryCode')); From fc83a2f685f99415284086936395c9bda24dc147 Mon Sep 17 00:00:00 2001 From: "LDFOUR\\luisd" Date: Fri, 28 Mar 2025 15:58:21 -0300 Subject: [PATCH 3/3] remove confg not used --- config/l5-swagger.php | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/config/l5-swagger.php b/config/l5-swagger.php index 7715ef0..469b108 100644 --- a/config/l5-swagger.php +++ b/config/l5-swagger.php @@ -48,21 +48,6 @@ ], ], ], - 'users' => [ - 'api' => [ - 'title' => 'API Usuarios Autenticados', - ], - 'routes' => [ - 'api' => 'api/users/documentation', - ], - 'paths' => [ - 'docs_json' => 'users-docs.json', - 'docs_yaml' => 'users-docs.yaml', - 'annotations' => [ - base_path('app/Http/Controllers/ApiUsers'), - ], - ], - ], ], 'defaults' => [ 'routes' => [