From 7f1a94275f5d466413c44b9895304ab83051d714 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 13 Oct 2025 15:02:10 -0300 Subject: [PATCH 1/7] feat: Extend Swagger Coverage for controller `OAuth2TagsApiController` --- .../Main/OAuth2TagsApiController.php | 158 +++++++++++++++++- app/Swagger/schemas.php | 39 ++++- 2 files changed, 195 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index 2e1f1f2a9..09f03eb0a 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -19,6 +19,8 @@ use ModelSerializers\SerializerRegistry; use Illuminate\Support\Facades\Request; use App\Services\Model\ITagService; +use Illuminate\Http\Response; +use OpenApi\Attributes as OA; /** * Class OAuth2TagsApiController * @package App\Http\Controllers @@ -54,6 +56,40 @@ public function __construct $this->tag_service = $tag_service; } + #[OA\Get( + path: "/api/v1/tags", + summary: "Get all tags", + description: "Returns a paginated list of tags. Allows ordering, filtering and pagination.", + security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], + tags: ["Tags"], + parameters: [ + new OA\Parameter(ref: "#/components/parameters/page_number_param"), + new OA\Parameter(ref: "#/components/parameters/page_size_param"), + new OA\Parameter( + name: "filter[]", + in: "query", + required: false, + description: "Filter tags. Available filters: tag (=@, ==, @@)", + schema: new OA\Schema(type: "array", items: new OA\Items(type: "string")), + explode: true + ), + new OA\Parameter( + name: "order", + in: "query", + required: false, + description: "Order by field. Valid fields: id, tag", + schema: new OA\Schema(type: "string") + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Success", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedTagsResponse") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + ] + )] public function getAll(){ return $this->_getAll( function () { @@ -88,6 +124,50 @@ function () { ); } + #[OA\Get( + path: "/api/v1/tags/{id}", + summary: "Get a specific tag", + description: "Returns detailed information about a specific tag", + tags: ["Tags"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + description: "Tag ID", + schema: new OA\Schema(type: "integer") + ), + new OA\Parameter( + name: "expand", + in: "query", + required: false, + description: "Expand related entities", + schema: new OA\Schema(type: "string") + ), + new OA\Parameter( + name: "fields", + in: "query", + required: false, + description: "Fields to include in response", + schema: new OA\Schema(type: "string") + ), + new OA\Parameter( + name: "relations", + in: "query", + required: false, + description: "Relations to include", + schema: new OA\Schema(type: "string") + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Success", + content: new OA\JsonContent(ref: "#/components/schemas/Tag") + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Tag not found"), + ] + )] public function getTag($tag_id){ return $this->processRequest(function () use ($tag_id) { $tag = $this->repository->getById(intval($tag_id)); @@ -104,6 +184,28 @@ public function getTag($tag_id){ }); } + #[OA\Post( + path: "/api/v1/tags", + summary: "Create a new tag", + description: "Creates a new tag", + security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], + tags: ["Tags"], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent(ref: "#/components/schemas/TagRequest") + ), + responses: [ + new OA\Response( + response: Response::HTTP_CREATED, + description: "Created", + content: new OA\JsonContent(ref: "#/components/schemas/Tag") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_FORBIDDEN, description: "Forbidden"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] public function addTag(){ return $this->processRequest(function () { if(!Request::isJson()) return $this->error400(); @@ -134,6 +236,38 @@ public function addTag(){ }); } + #[OA\Put( + path: "/api/v1/tags/{id}", + summary: "Update a tag", + description: "Updates an existing tag", + security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], + tags: ["Tags"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + description: "Tag ID", + schema: new OA\Schema(type: "integer") + ), + ], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent(ref: "#/components/schemas/TagRequest") + ), + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Success", + content: new OA\JsonContent(ref: "#/components/schemas/Tag") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_FORBIDDEN, description: "Forbidden"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Tag not found"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] public function updateTag($tag_id){ return $this->processRequest(function () use ($tag_id) { if(!Request::isJson()) return $this->error400(); @@ -166,6 +300,28 @@ public function updateTag($tag_id){ }); } + #[OA\Delete( + path: "/api/v1/tags/{id}", + summary: "Delete a tag", + description: "Deletes a tag", + security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], + tags: ["Tags"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + description: "Tag ID", + schema: new OA\Schema(type: "integer") + ), + ], + responses: [ + new OA\Response(response: Response::HTTP_NO_CONTENT, description: "Deleted successfully"), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_FORBIDDEN, description: "Forbidden"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Tag not found"), + ] + )] public function deleteTag($tag_id){ return $this->processRequest(function () use ($tag_id) { @@ -174,4 +330,4 @@ public function deleteTag($tag_id){ return $this->deleted(); }); } -} \ No newline at end of file +} diff --git a/app/Swagger/schemas.php b/app/Swagger/schemas.php index b940875b5..2ff72f38e 100644 --- a/app/Swagger/schemas.php +++ b/app/Swagger/schemas.php @@ -469,6 +469,41 @@ class ChunkedFileUploadRequestSchema { } +// Tag Schemas + +#[OA\Schema( + schema: "PaginatedTagsResponse", + description: "Paginated response for Tags", + properties: [ + new OA\Property(property: "total", type: "integer", example: 100), + new OA\Property(property: "per_page", type: "integer", example: 15), + new OA\Property(property: "current_page", type: "integer", example: 1), + new OA\Property(property: "last_page", type: "integer", example: 7), + new OA\Property( + property: "data", + type: "array", + items: new OA\Items(ref: "#/components/schemas/Tag") + ), + ], + type: "object" +)] +class PaginatedTagsResponseSchema +{ +} + +#[OA\Schema( + schema: "TagRequest", + description: "Request to create or update a Tag", + required: ["tag"], + properties: [ + new OA\Property(property: "tag", type: "string", maxLength: 100, example: "Cloud Computing"), + ], + type: "object" +)] +class TagRequestSchema +{ +} + #[OA\Schema( schema: 'PaginatedOrganizationsResponse', allOf: [ @@ -598,4 +633,6 @@ class PaymentGatewayProfileUpdateRequestSchema ) ] )] -class PaginatedUserStoriesResponseSchema {} +class PaginatedUserStoriesResponseSchema +{ +} \ No newline at end of file From df0753f706f48193c696823787561cbc589968b6 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 13 Oct 2025 18:21:47 -0300 Subject: [PATCH 2/7] fix: param definition --- .../Protected/Main/OAuth2TagsApiController.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index 09f03eb0a..20ffe753a 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -63,8 +63,20 @@ public function __construct security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], tags: ["Tags"], parameters: [ - new OA\Parameter(ref: "#/components/parameters/page_number_param"), - new OA\Parameter(ref: "#/components/parameters/page_size_param"), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer'), + description: 'The page number' + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer'), + description: 'The number of pages in each page', + ), new OA\Parameter( name: "filter[]", in: "query", From 4834efb9099f351e7749650658ceefe67d2c97a5 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Tue, 14 Oct 2025 14:56:22 -0300 Subject: [PATCH 3/7] fix: Change "namespace" word positioning --- .../Apis/Protected/Main/OAuth2TagsApiController.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index 20ffe753a..e72f097cf 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -1,4 +1,7 @@ -deleted(); }); } -} +} \ No newline at end of file From 6e11abd11605bd93be1cfbae69b741e22922544e Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Wed, 3 Dec 2025 19:03:00 +0000 Subject: [PATCH 4/7] feat: Add OAuth2 security scheme --- .../Main/OAuth2TagsApiController.php | 56 +++++++++++++++++-- app/Swagger/Security/TagsAuthSchema.php | 27 +++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 app/Swagger/Security/TagsAuthSchema.php diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index e72f097cf..3daebaf98 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -15,7 +15,9 @@ * limitations under the License. **/ +use App\Models\Foundation\Main\IGroup; use App\ModelSerializers\SerializerUtils; +use App\Security\SummitScopes; use models\main\ITagRepository; use models\oauth2\IResourceServerContext; use Illuminate\Support\Facades\Validator; @@ -61,10 +63,15 @@ public function __construct #[OA\Get( path: "/api/v1/tags", + operationId: "getAllTags", summary: "Get all tags", description: "Returns a paginated list of tags. Allows ordering, filtering and pagination.", - security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], tags: ["Tags"], + security: [['tags_oauth2' => [ + SummitScopes::ReadAllSummitData, + SummitScopes::ReadSummitData, + SummitScopes::ReadTagsData, + ]]], parameters: [ new OA\Parameter( name: 'page', @@ -141,9 +148,15 @@ function () { #[OA\Get( path: "/api/v1/tags/{id}", + operationId: "getTag", summary: "Get a specific tag", description: "Returns detailed information about a specific tag", tags: ["Tags"], + security: [['tags_oauth2' => [ + SummitScopes::ReadAllSummitData, + SummitScopes::ReadSummitData, + SummitScopes::ReadTagsData, + ]]], parameters: [ new OA\Parameter( name: "id", @@ -201,10 +214,21 @@ public function getTag($tag_id){ #[OA\Post( path: "/api/v1/tags", + operationId: "createTag", summary: "Create a new tag", description: "Creates a new tag", - security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], tags: ["Tags"], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ]]], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent(ref: "#/components/schemas/TagRequest") @@ -253,10 +277,21 @@ public function addTag(){ #[OA\Put( path: "/api/v1/tags/{id}", + operationId: "updateTag", summary: "Update a tag", description: "Updates an existing tag", - security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], tags: ["Tags"], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ]]], parameters: [ new OA\Parameter( name: "id", @@ -317,10 +352,21 @@ public function updateTag($tag_id){ #[OA\Delete( path: "/api/v1/tags/{id}", + operationId: "deleteTag", summary: "Delete a tag", description: "Deletes a tag", - security: [["oauth2_security_scope" => ["openid", "profile", "email"]]], tags: ["Tags"], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ]]], parameters: [ new OA\Parameter( name: "id", @@ -345,4 +391,4 @@ public function deleteTag($tag_id){ return $this->deleted(); }); } -} \ No newline at end of file +} diff --git a/app/Swagger/Security/TagsAuthSchema.php b/app/Swagger/Security/TagsAuthSchema.php new file mode 100644 index 000000000..d6cade4c3 --- /dev/null +++ b/app/Swagger/Security/TagsAuthSchema.php @@ -0,0 +1,27 @@ + 'Read All Summit Data', + SummitScopes::ReadSummitData => 'Read Summit Data', + SummitScopes::ReadTagsData => 'Read Tags Data', + SummitScopes::WriteSummitData => 'Write Summit Data', + SummitScopes::WriteTagsData => 'Write Tags Data', + ], + ), + ], + ) +] +class TagsAuthSchema {} From aa54c7bd4e9ba7b50a2bc724f6a1fa6c1df6f608 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 4 Dec 2025 13:25:45 +0000 Subject: [PATCH 5/7] feat: Add changes requested in PR --- .../Apis/Protected/Main/OAuth2TagsApiController.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index 3daebaf98..cdf5b9d3d 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -219,7 +219,7 @@ public function getTag($tag_id){ description: "Creates a new tag", tags: ["Tags"], x: [ - 'authz_groups' => [ + 'required-groups' => [ IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, @@ -282,7 +282,7 @@ public function addTag(){ description: "Updates an existing tag", tags: ["Tags"], x: [ - 'authz_groups' => [ + 'required-groups' => [ IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, @@ -357,7 +357,7 @@ public function updateTag($tag_id){ description: "Deletes a tag", tags: ["Tags"], x: [ - 'authz_groups' => [ + 'required-groups' => [ IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, From b75550614e6aed5c6edf608802a146c638041ee9 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 4 Dec 2025 17:57:14 +0000 Subject: [PATCH 6/7] feat: Add changes requested in PR --- .../Main/OAuth2TagsApiController.php | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php index cdf5b9d3d..4da5c92a5 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2TagsApiController.php @@ -67,11 +67,15 @@ public function __construct summary: "Get all tags", description: "Returns a paginated list of tags. Allows ordering, filtering and pagination.", tags: ["Tags"], - security: [['tags_oauth2' => [ - SummitScopes::ReadAllSummitData, - SummitScopes::ReadSummitData, - SummitScopes::ReadTagsData, - ]]], + security: [ + [ + 'tags_oauth2' => [ + SummitScopes::ReadAllSummitData, + SummitScopes::ReadSummitData, + SummitScopes::ReadTagsData, + ] + ] + ], parameters: [ new OA\Parameter( name: 'page', @@ -152,11 +156,15 @@ function () { summary: "Get a specific tag", description: "Returns detailed information about a specific tag", tags: ["Tags"], - security: [['tags_oauth2' => [ - SummitScopes::ReadAllSummitData, - SummitScopes::ReadSummitData, - SummitScopes::ReadTagsData, - ]]], + security: [ + [ + 'tags_oauth2' => [ + SummitScopes::ReadAllSummitData, + SummitScopes::ReadSummitData, + SummitScopes::ReadTagsData, + ] + ] + ], parameters: [ new OA\Parameter( name: "id", @@ -225,10 +233,14 @@ public function getTag($tag_id){ IGroup::SummitAdministrators, ] ], - security: [['tags_oauth2' => [ - SummitScopes::WriteSummitData, - SummitScopes::WriteTagsData, - ]]], + security: [ + [ + 'tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ] + ] + ], requestBody: new OA\RequestBody( required: true, content: new OA\JsonContent(ref: "#/components/schemas/TagRequest") @@ -288,10 +300,14 @@ public function addTag(){ IGroup::SummitAdministrators, ] ], - security: [['tags_oauth2' => [ - SummitScopes::WriteSummitData, - SummitScopes::WriteTagsData, - ]]], + security: [ + [ + 'tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ] + ] + ], parameters: [ new OA\Parameter( name: "id", @@ -363,10 +379,14 @@ public function updateTag($tag_id){ IGroup::SummitAdministrators, ] ], - security: [['tags_oauth2' => [ - SummitScopes::WriteSummitData, - SummitScopes::WriteTagsData, - ]]], + security: [ + [ + 'tags_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTagsData, + ] + ] + ], parameters: [ new OA\Parameter( name: "id", From 808ad49cf06214a66014f1e31c2c853bfb0c8c9f Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 29 Dec 2025 19:45:01 +0000 Subject: [PATCH 7/7] chore: Add missing properties in TagSchema Signed-off-by: Matias Perrone --- app/Swagger/Models/TagSchema.php | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/app/Swagger/Models/TagSchema.php b/app/Swagger/Models/TagSchema.php index 3166becf0..9022b364c 100644 --- a/app/Swagger/Models/TagSchema.php +++ b/app/Swagger/Models/TagSchema.php @@ -9,19 +9,10 @@ type: "object", required: ["id", "tag"], properties: [ - new OA\Property( - property: "id", - type: "integer", - format: "int64", - description: "Tag ID", - example: 1 - ), - new OA\Property( - property: "tag", - type: "string", - description: "Tag name/value", - example: "Beginner" - ), + new OA\Property(property: "id", type: "integer", example: 1), + new OA\Property(property: "created", type: "integer", format: "int64", description: "Creation timestamp (epoch)", example: 1234567890), + new OA\Property(property: "last_edited", type: "integer", format: "int64", description: "Last edit timestamp (epoch)", example: 1234567890), + new OA\Property(property: "tag", type: "string", maxLength: 100, example: "Cloud Computing"), ] )] class TagSchema {}