diff --git a/app/Console/Commands/GenerateSwaggerDocs.php b/app/Console/Commands/GenerateSwaggerDocs.php index 4947b8f5..5acabd0b 100644 --- a/app/Console/Commands/GenerateSwaggerDocs.php +++ b/app/Console/Commands/GenerateSwaggerDocs.php @@ -45,6 +45,8 @@ public function modifyOpenAPIJsonFile($filterPaths = [], $filePath = 'vendor/res $jsonData = json_decode(File::get($jsonFilePath), true); + $this->removeInvalidResponseStatusCodes($jsonData); + // Add security to non-public paths if (isset($jsonData['paths'])) { foreach ($jsonData['paths'] as $pathKey => &$path) { @@ -95,4 +97,30 @@ public function modifyOpenAPIJsonFile($filterPaths = [], $filePath = 'vendor/res File::put($jsonFilePath, $updatedJsonContents); } + + /** + * Remove response keys mangled by Lomkit's array_merge (e.g. "0", "\"500\""). + */ + private function removeInvalidResponseStatusCodes(array &$jsonData): void + { + foreach ($jsonData['paths'] ?? [] as &$path) { + foreach ($path as &$operation) { + if (! is_array($operation) || ! isset($operation['responses'])) { + continue; + } + + foreach (array_keys($operation['responses']) as $statusCode) { + if ($statusCode === 'default') { + continue; + } + + if (! ctype_digit((string) $statusCode)) { + unset($operation['responses'][$statusCode]); + } + } + } + } + + unset($path, $operation); + } } diff --git a/app/Documentation/Schemas/Responses.php b/app/Documentation/Schemas/Responses.php new file mode 100644 index 00000000..edfb1772 --- /dev/null +++ b/app/Documentation/Schemas/Responses.php @@ -0,0 +1,24 @@ +others = $this->others + $others; + + return $this; + } + + public function jsonSerialize(): mixed + { + return ['default' => $this->default()->jsonSerialize()] + + collect($this->others())->map->jsonSerialize()->toArray(); + } +} diff --git a/app/Providers/RestDocumentationServiceProvider.php b/app/Providers/RestDocumentationServiceProvider.php index d2320564..90047d53 100644 --- a/app/Providers/RestDocumentationServiceProvider.php +++ b/app/Providers/RestDocumentationServiceProvider.php @@ -2,6 +2,7 @@ namespace App\Providers; +use App\Documentation\Schemas\Responses; use Illuminate\Support\ServiceProvider; use Laravel\Fortify\Features; use Lomkit\Rest\Documentation\Schemas\Example; @@ -13,7 +14,6 @@ use Lomkit\Rest\Documentation\Schemas\Path; use Lomkit\Rest\Documentation\Schemas\RequestBody; use Lomkit\Rest\Documentation\Schemas\Response; -use Lomkit\Rest\Documentation\Schemas\Responses; use Lomkit\Rest\Documentation\Schemas\SchemaConcrete; use Lomkit\Rest\Facades\Rest; @@ -312,7 +312,7 @@ public function boot() ]) ) ->withOthers([ - json_encode('500') => (new Response) + '500' => (new Response) ->withDescription('Server Error') ->withContent([ 'application/json' => (new MediaType) @@ -422,7 +422,7 @@ public function boot() ->withDescription('Email verification successful and redirected') ) ->withOthers([ - json_encode('401') => (new Response) + '401' => (new Response) ->withDescription('Invalid/Expired URL provided') ->generate(), ]) diff --git a/app/Support/Csp/Policies/CoconutPolicy.php b/app/Support/Csp/Policies/CoconutPolicy.php index f1ea62de..7910bb68 100644 --- a/app/Support/Csp/Policies/CoconutPolicy.php +++ b/app/Support/Csp/Policies/CoconutPolicy.php @@ -28,7 +28,7 @@ public function configure(Policy $policy): void $policy ->add(Directive::SCRIPT, Keyword::SELF) ->add(Directive::STYLE, Keyword::SELF) - ->add(Directive::FONT, [Keyword::SELF, 'data:']) + ->add(Directive::FONT, [Keyword::SELF, 'data:', 'https://fonts.scalar.com']) ->add(Directive::CONNECT, Keyword::SELF); // Third-party services @@ -36,7 +36,7 @@ public function configure(Policy $policy): void ->add(Directive::STYLE, ['https://fonts.googleapis.com', 'https://unpkg.com', 'https://cdn.jsdelivr.net', 'https://fonts.bunny.net']) ->add(Directive::FONT, ['https://fonts.bunny.net']) ->add(Directive::SCRIPT, ['https://matomo.nfdi4chem.de', 'https://cdn.jsdelivr.net', 'https://unpkg.com']) - ->add(Directive::CONNECT, ['https://matomo.nfdi4chem.de', 'https://unpkg.com']) + ->add(Directive::CONNECT, ['https://matomo.nfdi4chem.de', 'https://unpkg.com', 'https://fonts.scalar.com']) ->add(Directive::IMG, 'https://matomo.nfdi4chem.de'); // Add Coconut-specific external sources diff --git a/docs/api-documentation.md b/docs/api-documentation.md index 12507dc1..3afd0964 100644 --- a/docs/api-documentation.md +++ b/docs/api-documentation.md @@ -35,7 +35,7 @@ POST /api/auth/login ``` :::info -The token is of **Bearer** type. This has to be supplied in the headers of the requests. In case you are using the [swagger UI of the API](https://coconut.naturalproducts.net/api-documentation), click on the **Authorize** button and provide the token as per the instruction. +The token is of **Bearer** type. This has to be supplied in the headers of the requests. In case you are using the [interactive API documentation](https://coconut.naturalproducts.net/api-documentation), open **Authentication** and provide the token as per the instruction. ::: ### Logout ``` diff --git a/public/vendor/rest/openapi.json b/public/vendor/rest/openapi.json index 118bc128..d301592e 100644 --- a/public/vendor/rest/openapi.json +++ b/public/vendor/rest/openapi.json @@ -1,11 +1,11 @@ { "openapi": "3.1.0", "info": { - "title": "COCONUT", + "title": "Laravel", "summary": "COlleCtion of Open NatUral producTs", "description": "A comprehensive platform facilitating natural product research by providing data, tools, and services for deposition, curation, and reuse.", "contact": { - "name": "COCONUT", + "name": "Laravel", "url": "https:\/\/coconut.naturalproducts.net\/", "email": "info.coconut@uni-jena.de" }, @@ -629,10 +629,10 @@ "application\/json": { "example": { "data": { - "title": "Est consectetur labore ut.", - "description": "Distinctio assumenda eum itaque veritatis in aut. Rem aut exercitationem occaecati rerum quo. Illo veritatis aut non non. Quia ipsum doloribus fugiat vel corrupti fugit quasi.", - "url": "http:\/\/crooks.com\/", - "identifier": null + "title": "Alias eos provident aperiam animi.", + "description": "Veritatis mollitia nesciunt et omnis magni. Quas est iusto natus repudiandae dolore cupiditate ratione. Enim adipisci dolores ipsa ut magnam. Ratione qui qui vel quisquam architecto.", + "url": "http:\/\/www.jaskolski.net\/quod-voluptates-tempore-qui-culpa-dolor-nobis", + "identifier": "Tempora placeat assumenda dolor at." }, "meta": [] } @@ -674,9 +674,9 @@ "application\/json": { "example": { "data": { - "title": "Et alias rerum incidunt et.", - "description": "Libero nesciunt placeat magnam sint. Ut in voluptas consequatur. Laborum aspernatur sint ut optio. Voluptatem illo distinctio culpa laborum.", - "url": "http:\/\/kutch.com\/ab-voluptatem-consequatur-minus-voluptas-repudiandae-perferendis", + "title": "Quos voluptatem voluptas in nemo eveniet.", + "description": "Quam est maxime nihil ut reiciendis rerum. Et et facilis et ea debitis maiores voluptate. Eum saepe ipsam libero dolor.", + "url": "https:\/\/www.green.com\/aperiam-voluptatum-dolor-fugit-similique-possimus-aut-aut", "identifier": null }, "meta": [] @@ -946,9 +946,9 @@ "application\/json": { "example": { "data": { - "doi": "10.1016\/j.bbrep.2025.102032~58", - "title": "RNA signaling in medicinal plants: An overlooked mechanism for phytochemical regulation.", - "authors": "Alum EU, Udechukwu CD, Obasi DC.", + "doi": "10.1007\/s11013-026-09992-1~86", + "title": "W\u00e8r\u00e8 and the Ontological Politics of Global Mental Health: Distributed Cognition in Yor\u00f9b\u00e1 Traditional Medicine.", + "authors": "Jegede O.", "citation_text": "" }, "meta": [] @@ -991,9 +991,9 @@ "application\/json": { "example": { "data": { - "doi": "10.1039\/b700306b~29", - "title": "Natural product isolation.", - "authors": "Sticher O.", + "doi": "10.1021\/acs.jnatprod.6c00295~37", + "title": "Systematic Assessment of the Impact of Targeted Selection Methods and Environment-Mimicking Culture Conditions on Fungal Natural Product Libraries.", + "authors": "Ness M, Wendt KL, Peramuna T, Tillery DI, Murray JE, Cichewicz RH, McCall LI.", "citation_text": "" }, "meta": [] @@ -1568,8 +1568,8 @@ "application\/json": { "example": { "data": { - "name": "Annabel Medhurst", - "email": "veum.adolphus@example.com" + "name": "Prof. Payton Wiza Sr.", + "email": "cronin.matilde@example.com" }, "meta": [] } @@ -1611,8 +1611,8 @@ "application\/json": { "example": { "data": { - "name": "Dr. Gonzalo Simonis II", - "email": "ssimonis@example.net" + "name": "Lloyd Wuckert", + "email": "vtreutel@example.org" }, "meta": [] } @@ -2535,7 +2535,8 @@ "title", "evidence", "comment", - "suggested_changes" + "suggested_changes", + "mol_ids" ], "scout_fields": [], "limits": [ @@ -2654,6 +2655,11 @@ "field": "suggested_changes", "operator": "=", "value": "" + }, + { + "field": "mol_ids", + "operator": "=", + "value": "" } ], "sorts": [ @@ -2668,6 +2674,10 @@ { "field": "comment", "direction": "desc" + }, + { + "field": "mol_ids", + "direction": "desc" } ], "selects": [ @@ -2682,6 +2692,9 @@ }, { "field": "suggested_changes" + }, + { + "field": "mol_ids" } ], "includes": [], @@ -2742,7 +2755,8 @@ "title": "", "evidence": "", "comment": "", - "suggested_changes": "" + "suggested_changes": "", + "mol_ids": "" }, "relations": [] } @@ -3035,7 +3049,7 @@ } } }, - "\"500\"": { + "500": { "description": "Server Error", "content": { "application\/json": { @@ -3063,6 +3077,75 @@ } } } + }, + "\/api\/auth\/verify\/{user_id}": { + "get": { + "tags": [ + "Authentication" + ], + "summary": "Email verification endpoint", + "responses": { + "default": { + "description": "Email verification successful and redirected", + "headers": { + "Location": { + "description": "URL to redirect to", + "schema": { + "type": "string" + } + }, + "Http-Response-Code": { + "description": "HTTP Response Code", + "schema": { + "type": "integer" + } + } + } + }, + "401": { + "description": "Invalid\/Expired URL provided" + } + }, + "requestBody": { + "content": { + "application\/json": { + "example": { + "user": { + "id": "example_user_id", + "name": "example_name", + "email": "example_email", + "password": "example_password" + }, + "signature": "example_signature" + } + } + }, + "description": "User object and Request Signature" + }, + "security": [ + { + "sanctum": [] + } + ] + } + }, + "\/api\/auth\/email\/resend": { + "get": { + "tags": [ + "Authentication" + ], + "summary": "Resend email verification endpoint", + "responses": { + "default": { + "description": "Email verification link sent to your email address" + } + }, + "security": [ + { + "sanctum": [] + } + ] + } } }, "servers": [ diff --git a/resources/views/vendor/rest/index.blade.php b/resources/views/vendor/rest/index.blade.php index 9e469a0e..384e00f4 100644 --- a/resources/views/vendor/rest/index.blade.php +++ b/resources/views/vendor/rest/index.blade.php @@ -3,20 +3,106 @@ - + {{ config('app.name') }} - API Documentation - + + - -
- + +
+ + {{ config('app.name') }} + + API Documentation +
+
+