From 1b921e229cbe90963deae56353ec9527c19d9b73 Mon Sep 17 00:00:00 2001 From: Jose Andres Tejerina Date: Wed, 22 Oct 2025 16:55:17 -0300 Subject: [PATCH 1/7] feat: Extend Swagger Coverage for controller OAuth2SponsoredProjectApiController --- .../OAuth2SponsoredProjectApiController.php | 181 ++++++++++++++++++ app/Swagger/SponsoredProjectSchemas.php | 118 ++++++++++++ 2 files changed, 299 insertions(+) create mode 100644 app/Swagger/SponsoredProjectSchemas.php diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php index f5a5d3544..e1d9fd920 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php @@ -17,6 +17,7 @@ use App\Models\Foundation\Main\Repositories\ISupportingCompanyRepository; use App\Services\Model\ISponsoredProjectService; use Illuminate\Http\Request as LaravelRequest; +use Illuminate\Http\Response; use Illuminate\Support\Facades\Log; use libs\utils\HTMLCleaner; use models\exceptions\EntityNotFoundException; @@ -28,6 +29,8 @@ use utils\Filter; use utils\FilterElement; use utils\PagingInfo; +use OpenApi\Attributes as OA; + /** * Class OAuth2SponsoredProjectApiController * @package App\Http\Controllers @@ -180,6 +183,71 @@ function () { // sponsorship types + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types", + description: "Get all sponsorship types for a sponsored project", + summary: 'Read All Sponsorship Types', + operationId: 'getAllSponsorshipTypes', + tags: ['Sponsored Projects', 'Sponsorship Types'], + security: [['oauth2' => ['read']]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string', example: 'name@@type') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'order,name') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of sponsorship types', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedProjectSponsorshipTypesResponse') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id string|int */ @@ -232,6 +300,47 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { ); } + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}", + description: "Get a specific sponsorship type", + summary: 'Read Sponsorship Type', + operationId: 'getSponsorshipType', + tags: ['Sponsored Projects', 'Sponsorship Types'], + security: [['oauth2' => ['read']]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsorship type details', + content: new OA\JsonContent(ref: '#/components/schemas/ProjectSponsorshipType') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -299,6 +408,78 @@ function ($sponsorship_type_id, $project_id){ // supporting companies + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies", + description: "Get all supporting companies for a sponsorship type", + summary: 'Read All Supporting Companies', + operationId: 'getSupportingCompanies', + tags: ['Sponsored Projects', 'Supporting Companies'], + security: [['oauth2' => ['read']]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsorship type id or slug' + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'order,name') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of supporting companies', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedSupportingCompaniesResponse') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] public function getSupportingCompanies($id, $sponsorship_type_id){ return $this->_getAll( function () { diff --git a/app/Swagger/SponsoredProjectSchemas.php b/app/Swagger/SponsoredProjectSchemas.php new file mode 100644 index 000000000..3680afc95 --- /dev/null +++ b/app/Swagger/SponsoredProjectSchemas.php @@ -0,0 +1,118 @@ + Date: Fri, 5 Dec 2025 21:44:50 +0000 Subject: [PATCH 2/7] fix: route path, tags, add missing routes, other missing doc properties --- .../OAuth2SponsoredProjectApiController.php | 851 +++++++++++++++++- app/Swagger/SponsoredProjectSchemas.php | 24 +- 2 files changed, 868 insertions(+), 7 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php index e1d9fd920..bd4ce47e7 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php @@ -12,20 +12,20 @@ * limitations under the License. **/ +use App\Models\Foundation\Main\IGroup; use App\Models\Foundation\Main\Repositories\IProjectSponsorshipTypeRepository; use App\Models\Foundation\Main\Repositories\ISponsoredProjectRepository; use App\Models\Foundation\Main\Repositories\ISupportingCompanyRepository; +use App\Security\SponsoredProjectScope; use App\Services\Model\ISponsoredProjectService; use Illuminate\Http\Request as LaravelRequest; use Illuminate\Http\Response; use Illuminate\Support\Facades\Log; use libs\utils\HTMLCleaner; use models\exceptions\EntityNotFoundException; -use models\main\SponsoredProject; use models\oauth2\IResourceServerContext; use models\utils\IEntity; use ModelSerializers\SerializerRegistry; -use Psr\Log\LogLevel; use utils\Filter; use utils\FilterElement; use utils\PagingInfo; @@ -146,6 +146,65 @@ protected function updateEntity($id, array $payload): IEntity return $this->service->update(intval($id), HTMLCleaner::cleanData($payload, ['description'])); } + #[OA\Get( + path: "/api/v1/sponsored-projects", + description: "Get all sponsored projects", + summary: 'Read All Sponsored Projects', + operationId: 'getAllSponsoredProjects', + tags: ['Sponsored Projects'], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string', example: 'name@@project') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'name,id') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of sponsored projects', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedSponsoredProjectsResponse') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @return mixed */ @@ -181,6 +240,203 @@ function () { ); } + #[OA\Post( + path: "/api/v1/sponsored-projects", + description: "Add a new sponsored project", + summary: 'Add Sponsored Project', + operationId: 'addSponsoredProject', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Project name'), + new OA\Property(property: 'description', type: 'string', description: 'Project description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the project is active'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + ], + responses: [ + new OA\Response( + response: 201, + description: 'Sponsored project created', + content: new OA\JsonContent(ref: '#/components/schemas/SponsoredProject') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] + public function add() + { + return parent::add(); + } + + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}", + description: "Get a specific sponsored project", + summary: 'Read Sponsored Project', + operationId: 'getSponsoredProject', + tags: ['Sponsored Projects'], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsored project details', + content: new OA\JsonContent(ref: '#/components/schemas/SponsoredProject') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] + public function get($id) + { + return parent::get($id); + } + + #[OA\Put( + path: "/api/v1/sponsored-projects/{id}", + description: "Update a sponsored project", + summary: 'Update Sponsored Project', + operationId: 'updateSponsoredProject', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Project name'), + new OA\Property(property: 'description', type: 'string', description: 'Project description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the project is active'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsored project updated', + content: new OA\JsonContent(ref: '#/components/schemas/SponsoredProject') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] + public function update($id) + { + return parent::update($id); + } + + #[OA\Delete( + path: "/api/v1/sponsored-projects/{id}", + description: "Delete a sponsored project", + summary: 'Delete Sponsored Project', + operationId: 'deleteSponsoredProject', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 204, + description: 'Sponsored project deleted', + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] + public function delete($id) + { + return parent::delete($id); + } + // sponsorship types #[OA\Get( @@ -189,7 +445,9 @@ function () { summary: 'Read All Sponsorship Types', operationId: 'getAllSponsorshipTypes', tags: ['Sponsored Projects', 'Sponsorship Types'], - security: [['oauth2' => ['read']]], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], parameters: [ new OA\Parameter( name: 'access_token', @@ -306,7 +564,9 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { summary: 'Read Sponsorship Type', operationId: 'getSponsorshipType', tags: ['Sponsored Projects', 'Sponsorship Types'], - security: [['oauth2' => ['read']]], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], parameters: [ new OA\Parameter( name: 'access_token', @@ -352,6 +612,61 @@ public function getSponsorshipType($id, $sponsorship_type_id){ }); } + #[OA\Post( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types", + description: "Add a new sponsorship type to a sponsored project", + summary: 'Add Sponsorship Type', + operationId: 'addSponsorshipType', + tags: ['Sponsored Projects', 'Sponsorship Types'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), + new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 201, + description: 'Sponsorship type created', + content: new OA\JsonContent(ref: '#/components/schemas/ProjectSponsorshipType') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] /** * @param $id * @return mixed @@ -370,6 +685,68 @@ function ($payload, $id){ ); } + #[OA\Put( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}", + description: "Update a sponsorship type", + summary: 'Update Sponsorship Type', + operationId: 'updateSponsorshipType', + tags: ['Sponsored Projects', 'Sponsorship Types'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), + new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsorship type updated', + content: new OA\JsonContent(ref: '#/components/schemas/ProjectSponsorshipType') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -389,6 +766,54 @@ function($sponsorship_type_id, $payload, $project_id){ ); } + #[OA\Delete( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}", + description: "Delete a sponsorship type", + summary: 'Delete Sponsorship Type', + operationId: 'deleteSponsorshipType', + tags: ['Sponsored Projects', 'Sponsorship Types'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + ], + responses: [ + new OA\Response( + response: 204, + description: 'Sponsorship type deleted', + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -414,7 +839,9 @@ function ($sponsorship_type_id, $project_id){ summary: 'Read All Supporting Companies', operationId: 'getSupportingCompanies', tags: ['Sponsored Projects', 'Supporting Companies'], - security: [['oauth2' => ['read']]], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], parameters: [ new OA\Parameter( name: 'access_token', @@ -529,6 +956,67 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { } + #[OA\Post( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies", + description: "Add a supporting company to a sponsorship type", + summary: 'Add Supporting Company', + operationId: 'addSupportingCompany', + tags: ['Sponsored Projects', 'Supporting Companies'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + required: ['company_id'], + properties: [ + new OA\Property(property: 'company_id', type: 'integer', description: 'The company id'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + ], + responses: [ + new OA\Response( + response: 201, + description: 'Supporting company added', + content: new OA\JsonContent(ref: '#/components/schemas/SupportingCompany') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -555,6 +1043,72 @@ function($payload, $project_id, $sponsorship_type_id){ ); } + #[OA\Put( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies/{company_id}", + description: "Update a supporting company", + summary: 'Update Supporting Company', + operationId: 'updateSupportingCompany', + tags: ['Sponsored Projects', 'Supporting Companies'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent( + type: 'object', + properties: [ + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + new OA\Parameter( + name: 'company_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The supporting company id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Supporting company updated', + content: new OA\JsonContent(ref: '#/components/schemas/SupportingCompany') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -582,6 +1136,61 @@ function($id, $payload, $project_id, $sponsorship_type_id){ ); } + #[OA\Delete( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies/{company_id}", + description: "Delete a supporting company from a sponsorship type", + summary: 'Delete Supporting Company', + operationId: 'deleteSupportingCompany', + tags: ['Sponsored Projects', 'Supporting Companies'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + new OA\Parameter( + name: 'company_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The supporting company id' + ), + ], + responses: [ + new OA\Response( + response: 204, + description: 'Supporting company deleted', + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -594,6 +1203,62 @@ public function deleteSupportingCompanies($id, $sponsorship_type_id, $company_id }, $id, $sponsorship_type_id); } + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies/{company_id}", + description: "Get a specific supporting company", + summary: 'Read Supporting Company', + operationId: 'getSupportingCompany', + tags: ['Sponsored Projects', 'Supporting Companies'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + new OA\Parameter( + name: 'company_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The supporting company id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Supporting company details', + content: new OA\JsonContent(ref: '#/components/schemas/SupportingCompany') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id * @param $sponsorship_type_id @@ -609,6 +1274,66 @@ public function getSupportingCompany($id, $sponsorship_type_id, $company_id){ }, $company_id); } + #[OA\Post( + path: "/api/v1/sponsored-projects/{id}/logo", + description: "Upload a logo for a sponsored project", + summary: 'Add Sponsored Project Logo', + operationId: 'addSponsoredProjectLogo', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + requestBody: new OA\RequestBody( + required: true, + content: new OA\MediaType( + mediaType: 'multipart/form-data', + schema: new OA\Schema( + type: 'object', + required: ['file'], + properties: [ + new OA\Property( + property: 'file', + type: 'string', + format: 'binary', + description: 'The logo file to upload' + ), + ] + ) + ) + ), + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 201, + description: 'Logo uploaded successfully', + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + ] + )] /** * @param LaravelRequest $request * @param $project_id @@ -627,6 +1352,47 @@ public function addSponsoredProjectLogo(LaravelRequest $request, $project_id) }); } + #[OA\Delete( + path: "/api/v1/sponsored-projects/{id}/logo", + description: "Delete the logo of a sponsored project", + summary: 'Delete Sponsored Project Logo', + operationId: 'deleteSponsoredProjectLogo', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Write, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + ], + responses: [ + new OA\Response( + response: 204, + description: 'Logo deleted successfully', + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $project_id * @return \Illuminate\Http\JsonResponse|mixed @@ -640,6 +1406,79 @@ public function deleteSponsoredProjectLogo($project_id){ // subprojects + #[OA\Get( + path: "/api/v1/sponsored-projects/{id}/subprojects", + description: "Get all subprojects of a sponsored project", + summary: 'Read Subprojects', + operationId: 'getSubprojects', + tags: ['Sponsored Projects'], + x: [ + 'authz_groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + ] + ], + security: [['sponsored_projects_oauth2' => [ + SponsoredProjectScope::Read, + ]]], + parameters: [ + new OA\Parameter( + name: 'access_token', + in: 'query', + required: false, + description: 'OAuth2 access token (alternative to Authorization: Bearer)', + schema: new OA\Schema(type: 'string', example: 'eyJhbGciOi...'), + ), + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsored project id' + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string', example: 'name@@subproject') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'name,id') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of subprojects', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedSponsoredProjectsResponse') + ), + new OA\Response(response: Response::HTTP_UNAUTHORIZED, description: "Unauthorized"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $id string|int */ @@ -677,4 +1516,4 @@ function () { } ); } -} \ No newline at end of file +} diff --git a/app/Swagger/SponsoredProjectSchemas.php b/app/Swagger/SponsoredProjectSchemas.php index 3680afc95..674d8f8fa 100644 --- a/app/Swagger/SponsoredProjectSchemas.php +++ b/app/Swagger/SponsoredProjectSchemas.php @@ -1,5 +1,8 @@ 'Read Sponsored Projects', + SponsoredProjectScope::Write => 'Write Sponsored Projects', + ], + ), + ], + ) +] +class SponsoredProjectsAuthSchema {} From 61e5bdad98d90dac4c0ed908bc5e4d03f5b7b2d5 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 8 Dec 2025 13:15:31 +0000 Subject: [PATCH 3/7] feat: add public routes --- .../OAuth2SponsoredProjectApiController.php | 232 +++++++++++++++++- 1 file changed, 228 insertions(+), 4 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php index bd4ce47e7..ba51fd789 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php @@ -146,6 +146,54 @@ protected function updateEntity($id, array $payload): IEntity return $this->service->update(intval($id), HTMLCleaner::cleanData($payload, ['description'])); } + #[OA\Get( + path: "/api/public/v1/sponsored-projects", + description: "Get all sponsored projects (public endpoint)", + summary: 'Read All Sponsored Projects (Public)', + operationId: 'getAllSponsoredProjectsPublic', + tags: ['Sponsored Projects'], + parameters: [ + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string', example: 'name@@project') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'name,id') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of sponsored projects', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedSponsoredProjectsResponse') + ), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] #[OA\Get( path: "/api/v1/sponsored-projects", description: "Get all sponsored projects", @@ -167,7 +215,7 @@ protected function updateEntity($id, array $payload): IEntity name: 'filter[]', in: 'query', required: false, - description: 'Filter expressions in the format fieldvalue', + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', style: 'form', explode: true, schema: new OA\Schema( @@ -291,6 +339,31 @@ public function add() return parent::add(); } + #[OA\Get( + path: "/api/public/v1/sponsored-projects/{id}", + description: "Get a specific sponsored project (public endpoint)", + summary: 'Read Sponsored Project (Public)', + operationId: 'getSponsoredProjectPublic', + tags: ['Sponsored Projects'], + parameters: [ + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsored project details', + content: new OA\JsonContent(ref: '#/components/schemas/SponsoredProject') + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] #[OA\Get( path: "/api/v1/sponsored-projects/{id}", description: "Get a specific sponsored project", @@ -439,6 +512,62 @@ public function delete($id) // sponsorship types + #[OA\Get( + path: "/api/public/v1/sponsored-projects/{id}/sponsorship-types", + description: "Get all sponsorship types for a sponsored project (public endpoint)", + summary: 'Read All Sponsorship Types (Public)', + operationId: 'getAllSponsorshipTypesPublic', + tags: ['Sponsored Projects', 'Sponsorship Types'], + parameters: [ + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string', example: 'name@@type') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'order,name') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of sponsorship types', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedProjectSponsorshipTypesResponse') + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] #[OA\Get( path: "/api/v1/sponsored-projects/{id}/sponsorship-types", description: "Get all sponsorship types for a sponsored project", @@ -467,7 +596,7 @@ public function delete($id) name: 'filter[]', in: 'query', required: false, - description: 'Filter expressions in the format fieldvalue', + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', style: 'form', explode: true, schema: new OA\Schema( @@ -558,6 +687,38 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { ); } + #[OA\Get( + path: "/api/public/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}", + description: "Get a specific sponsorship type (public endpoint)", + summary: 'Read Sponsorship Type (Public)', + operationId: 'getSponsorshipTypePublic', + tags: ['Sponsored Projects', 'Sponsorship Types'], + parameters: [ + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'integer'), + description: 'The sponsorship type id' + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'Sponsorship type details', + content: new OA\JsonContent(ref: '#/components/schemas/ProjectSponsorshipType') + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] #[OA\Get( path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}", description: "Get a specific sponsorship type", @@ -833,6 +994,69 @@ function ($sponsorship_type_id, $project_id){ // supporting companies + #[OA\Get( + path: "/api/public/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies", + description: "Get all supporting companies for a sponsorship type (public endpoint)", + summary: 'Read All Supporting Companies (Public)', + operationId: 'getSupportingCompaniesPublic', + tags: ['Sponsored Projects', 'Supporting Companies'], + parameters: [ + new OA\Parameter( + name: 'id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsored project id or slug' + ), + new OA\Parameter( + name: 'sponsorship_type_id', + in: 'path', + required: true, + schema: new OA\Schema(type: 'string'), + description: 'The sponsorship type id or slug' + ), + new OA\Parameter( + name: 'filter[]', + in: 'query', + required: false, + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', + style: 'form', + explode: true, + schema: new OA\Schema( + type: 'array', + items: new OA\Items(type: 'string') + ) + ), + new OA\Parameter( + name: 'order', + in: 'query', + required: false, + description: 'Order by field(s)', + schema: new OA\Schema(type: 'string', example: 'order,name') + ), + new OA\Parameter( + name: 'page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 1) + ), + new OA\Parameter( + name: 'per_page', + in: 'query', + required: false, + schema: new OA\Schema(type: 'integer', default: 10) + ), + ], + responses: [ + new OA\Response( + response: 200, + description: 'List of supporting companies', + content: new OA\JsonContent(ref: '#/components/schemas/PaginatedSupportingCompaniesResponse') + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] #[OA\Get( path: "/api/v1/sponsored-projects/{id}/sponsorship-types/{sponsorship_type_id}/supporting-companies", description: "Get all supporting companies for a sponsorship type", @@ -868,7 +1092,7 @@ function ($sponsorship_type_id, $project_id){ name: 'filter[]', in: 'query', required: false, - description: 'Filter expressions', + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', style: 'form', explode: true, schema: new OA\Schema( @@ -1440,7 +1664,7 @@ public function deleteSponsoredProjectLogo($project_id){ name: 'filter[]', in: 'query', required: false, - description: 'Filter expressions in the format fieldvalue', + description: 'Filter expressions in the format fieldvalue, operators: =@ (starts with), == (equals), @@ (contains), fields: name, slug, is_active', style: 'form', explode: true, schema: new OA\Schema( From cd0facca224cc112bfb2e00f0fb3ac79341c39aa Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 8 Dec 2025 13:17:42 +0000 Subject: [PATCH 4/7] chore: Add "(Public)" to public endpoints tags --- .../Main/OAuth2SponsoredProjectApiController.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php index ba51fd789..dda717328 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php @@ -151,7 +151,7 @@ protected function updateEntity($id, array $payload): IEntity description: "Get all sponsored projects (public endpoint)", summary: 'Read All Sponsored Projects (Public)', operationId: 'getAllSponsoredProjectsPublic', - tags: ['Sponsored Projects'], + tags: ['Sponsored Projects (Public)'], parameters: [ new OA\Parameter( name: 'filter[]', @@ -344,7 +344,7 @@ public function add() description: "Get a specific sponsored project (public endpoint)", summary: 'Read Sponsored Project (Public)', operationId: 'getSponsoredProjectPublic', - tags: ['Sponsored Projects'], + tags: ['Sponsored Projects (Public)'], parameters: [ new OA\Parameter( name: 'id', @@ -517,7 +517,7 @@ public function delete($id) description: "Get all sponsorship types for a sponsored project (public endpoint)", summary: 'Read All Sponsorship Types (Public)', operationId: 'getAllSponsorshipTypesPublic', - tags: ['Sponsored Projects', 'Sponsorship Types'], + tags: ['Sponsored Projects (Public)', 'Sponsorship Types (Public)'], parameters: [ new OA\Parameter( name: 'id', @@ -692,7 +692,7 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { description: "Get a specific sponsorship type (public endpoint)", summary: 'Read Sponsorship Type (Public)', operationId: 'getSponsorshipTypePublic', - tags: ['Sponsored Projects', 'Sponsorship Types'], + tags: ['Sponsored Projects (Public)', 'Sponsorship Types (Public)'], parameters: [ new OA\Parameter( name: 'id', @@ -999,7 +999,7 @@ function ($sponsorship_type_id, $project_id){ description: "Get all supporting companies for a sponsorship type (public endpoint)", summary: 'Read All Supporting Companies (Public)', operationId: 'getSupportingCompaniesPublic', - tags: ['Sponsored Projects', 'Supporting Companies'], + tags: ['Sponsored Projects (Public)', 'Supporting Companies (Public)'], parameters: [ new OA\Parameter( name: 'id', From 214745ba0bdaeb5ed47d32b499abc3c9f34f5e1e Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 8 Dec 2025 13:47:55 +0000 Subject: [PATCH 5/7] fix: documentation build issues --- .../Models/ProjectSponsorshipTypeSchema.php | 2 +- .../Models/SupportingCompanySchema.php | 2 +- .../Security/SponsoredProjectsAuthSchema.php | 24 ++++++ ...h2.php => SummitAdminGroupsAuthSchema.php} | 0 ...tBookableRoomsAttributeTypeAuthSchema.php} | 0 app/Swagger/SponsoredProjectSchemas.php | 81 +------------------ 6 files changed, 29 insertions(+), 80 deletions(-) create mode 100644 app/Swagger/Security/SponsoredProjectsAuthSchema.php rename app/Swagger/Security/{SummitAdminGroupsOauth2.php => SummitAdminGroupsAuthSchema.php} (100%) rename app/Swagger/{security/SummitBookableRoomsAttributeTypeSecurity.php => Security/SummitBookableRoomsAttributeTypeAuthSchema.php} (100%) diff --git a/app/Swagger/Models/ProjectSponsorshipTypeSchema.php b/app/Swagger/Models/ProjectSponsorshipTypeSchema.php index ca9b262e5..1bbf6d4fb 100644 --- a/app/Swagger/Models/ProjectSponsorshipTypeSchema.php +++ b/app/Swagger/Models/ProjectSponsorshipTypeSchema.php @@ -33,4 +33,4 @@ )] class ProjectSponsorshipTypeSchema { -} \ No newline at end of file +} diff --git a/app/Swagger/Models/SupportingCompanySchema.php b/app/Swagger/Models/SupportingCompanySchema.php index b52ce3d56..383e37550 100644 --- a/app/Swagger/Models/SupportingCompanySchema.php +++ b/app/Swagger/Models/SupportingCompanySchema.php @@ -22,4 +22,4 @@ ] class SupportingCompanySchema { -} \ No newline at end of file +} diff --git a/app/Swagger/Security/SponsoredProjectsAuthSchema.php b/app/Swagger/Security/SponsoredProjectsAuthSchema.php new file mode 100644 index 000000000..653a34c55 --- /dev/null +++ b/app/Swagger/Security/SponsoredProjectsAuthSchema.php @@ -0,0 +1,24 @@ + 'Read Sponsored Projects', + SponsoredProjectScope::Write => 'Write Sponsored Projects', + ], + ), + ], + ) +] +class SponsoredProjectsAuthSchema {} diff --git a/app/Swagger/Security/SummitAdminGroupsOauth2.php b/app/Swagger/Security/SummitAdminGroupsAuthSchema.php similarity index 100% rename from app/Swagger/Security/SummitAdminGroupsOauth2.php rename to app/Swagger/Security/SummitAdminGroupsAuthSchema.php diff --git a/app/Swagger/security/SummitBookableRoomsAttributeTypeSecurity.php b/app/Swagger/Security/SummitBookableRoomsAttributeTypeAuthSchema.php similarity index 100% rename from app/Swagger/security/SummitBookableRoomsAttributeTypeSecurity.php rename to app/Swagger/Security/SummitBookableRoomsAttributeTypeAuthSchema.php diff --git a/app/Swagger/SponsoredProjectSchemas.php b/app/Swagger/SponsoredProjectSchemas.php index 674d8f8fa..45a2bcb20 100644 --- a/app/Swagger/SponsoredProjectSchemas.php +++ b/app/Swagger/SponsoredProjectSchemas.php @@ -2,27 +2,8 @@ namespace App\Swagger\schemas; -use App\Security\SponsoredProjectScope; use OpenApi\Attributes as OA; -#[OA\Schema( - schema: 'SponsoredProject', - title: 'SponsoredProject', - description: 'Represents a Sponsored Project', - type: 'object', - required: ['name'], - properties: [ - new OA\Property(property: 'id', type: 'integer', format: 'int64'), - new OA\Property(property: 'name', type: 'string'), - new OA\Property(property: 'slug', type: 'string'), - new OA\Property(property: 'description', type: 'string'), - new OA\Property(property: 'is_active', type: 'boolean'), - new OA\Property(property: 'created', type: 'integer', format: 'int64'), - new OA\Property(property: 'last_edited', type: 'integer', format: 'int64'), - ] -)] -class SponsoredProjectSchemas {} - #[OA\Schema( schema: 'PaginatedSponsoredProjectsResponse', title: 'Paginated Sponsored Projects', @@ -41,27 +22,7 @@ class SponsoredProjectSchemas {} ) ] )] -class PaginatedSponsoredProjectsResponse {} - -#[OA\Schema( - schema: 'ProjectSponsorshipType', - title: 'Project Sponsorship Type', - description: 'Represents a Project Sponsorship Type', - type: 'object', - required: ['name'], - properties: [ - new OA\Property(property: 'id', type: 'integer', format: 'int64'), - new OA\Property(property: 'name', type: 'string'), - new OA\Property(property: 'slug', type: 'string'), - new OA\Property(property: 'description', type: 'string'), - new OA\Property(property: 'is_active', type: 'boolean'), - new OA\Property(property: 'order', type: 'integer'), - new OA\Property(property: 'sponsored_project_id', type: 'integer', format: 'int64'), - new OA\Property(property: 'created', type: 'integer', format: 'int64'), - new OA\Property(property: 'last_edited', type: 'integer', format: 'int64'), - ] -)] -class ProjectSponsorshipType {} +class PaginatedSponsoredProjectsResponseSchema {} #[OA\Schema( schema: 'PaginatedProjectSponsorshipTypesResponse', @@ -81,24 +42,7 @@ class ProjectSponsorshipType {} ) ] )] -class PaginatedProjectSponsorshipTypesResponse {} - -#[OA\Schema( - schema: 'SupportingCompany', - title: 'Supporting Company', - description: 'Represents a Supporting Company for a Sponsorship Type', - type: 'object', - required: ['company_id'], - properties: [ - new OA\Property(property: 'id', type: 'integer', format: 'int64'), - new OA\Property(property: 'company_id', type: 'integer', format: 'int64'), - new OA\Property(property: 'sponsorship_type_id', type: 'integer', format: 'int64'), - new OA\Property(property: 'order', type: 'integer'), - new OA\Property(property: 'created', type: 'integer', format: 'int64'), - new OA\Property(property: 'last_edited', type: 'integer', format: 'int64'), - ] -)] -class SupportingCompany {} +class PaginatedProjectSponsorshipTypesResponseSchema {} #[OA\Schema( schema: 'PaginatedSupportingCompaniesResponse', @@ -118,23 +62,4 @@ class SupportingCompany {} ) ] )] -class PaginatedSupportingCompaniesResponse {} - -#[ - OA\SecurityScheme( - type: 'oauth2', - securityScheme: 'sponsored_projects_oauth2', - flows: [ - new OA\Flow( - authorizationUrl: L5_SWAGGER_CONST_AUTH_URL, - tokenUrl: L5_SWAGGER_CONST_TOKEN_URL, - flow: 'authorizationCode', - scopes: [ - SponsoredProjectScope::Read => 'Read Sponsored Projects', - SponsoredProjectScope::Write => 'Write Sponsored Projects', - ], - ), - ], - ) -] -class SponsoredProjectsAuthSchema {} +class PaginatedSupportingCompaniesResponseSchema {} From d75db08a75b6791798ffcb9d011378caf1e54ff1 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 8 Dec 2025 13:49:26 +0000 Subject: [PATCH 6/7] chore: rebuild docs --- app/Swagger/SponsoredProjectSchemas.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Swagger/SponsoredProjectSchemas.php b/app/Swagger/SponsoredProjectSchemas.php index 45a2bcb20..0d851e02b 100644 --- a/app/Swagger/SponsoredProjectSchemas.php +++ b/app/Swagger/SponsoredProjectSchemas.php @@ -63,3 +63,4 @@ class PaginatedProjectSponsorshipTypesResponseSchema {} ] )] class PaginatedSupportingCompaniesResponseSchema {} + From d9cc66de72692ea379cded3cdcf1ad713661a052 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 8 Dec 2025 14:27:10 +0000 Subject: [PATCH 7/7] feat: Add requestBody ref schemas --- .../OAuth2SponsoredProjectApiController.php | 67 ++--------------- app/Swagger/SponsoredProjectSchemas.php | 73 +++++++++++++++++++ 2 files changed, 80 insertions(+), 60 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php index dda717328..408d10f4c 100644 --- a/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php +++ b/app/Http/Controllers/Apis/Protected/Main/OAuth2SponsoredProjectApiController.php @@ -305,14 +305,7 @@ function () { ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - properties: [ - new OA\Property(property: 'name', type: 'string', description: 'Project name'), - new OA\Property(property: 'description', type: 'string', description: 'Project description'), - new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the project is active'), - ] - ) + content: new OA\JsonContent(ref:'#/components/schemas/SponsoredProjectRequest') ), parameters: [ new OA\Parameter( @@ -422,14 +415,7 @@ public function get($id) ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - properties: [ - new OA\Property(property: 'name', type: 'string', description: 'Project name'), - new OA\Property(property: 'description', type: 'string', description: 'Project description'), - new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the project is active'), - ] - ) + content: new OA\JsonContent(ref: '#/components/schemas/SponsoredProjectRequest') ), parameters: [ new OA\Parameter( @@ -790,15 +776,7 @@ public function getSponsorshipType($id, $sponsorship_type_id){ ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - properties: [ - new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), - new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), - new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), - new OA\Property(property: 'order', type: 'integer', description: 'Display order'), - ] - ) + content: new OA\JsonContent(ref:'#/components/schemas/ProjectSponsorshipTypeCreateRequest') ), parameters: [ new OA\Parameter( @@ -863,15 +841,7 @@ function ($payload, $id){ ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - properties: [ - new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), - new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), - new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), - new OA\Property(property: 'order', type: 'integer', description: 'Display order'), - ] - ) + content: new OA\JsonContent(ref: '#/components/schemas/ProjectSponsorshipTypeUpdateRequest') ), parameters: [ new OA\Parameter( @@ -1197,14 +1167,7 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) { ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - required: ['company_id'], - properties: [ - new OA\Property(property: 'company_id', type: 'integer', description: 'The company id'), - new OA\Property(property: 'order', type: 'integer', description: 'Display order'), - ] - ) + content: new OA\JsonContent(ref: '#/components/schemas/AddSupportingCompanyRequest') ), parameters: [ new OA\Parameter( @@ -1284,12 +1247,7 @@ function($payload, $project_id, $sponsorship_type_id){ ]]], requestBody: new OA\RequestBody( required: true, - content: new OA\JsonContent( - type: 'object', - properties: [ - new OA\Property(property: 'order', type: 'integer', description: 'Display order'), - ] - ) + content: new OA\JsonContent(ref: '#/components/schemas/UpdateSupportingCompanyRequest') ), parameters: [ new OA\Parameter( @@ -1517,18 +1475,7 @@ public function getSupportingCompany($id, $sponsorship_type_id, $company_id){ required: true, content: new OA\MediaType( mediaType: 'multipart/form-data', - schema: new OA\Schema( - type: 'object', - required: ['file'], - properties: [ - new OA\Property( - property: 'file', - type: 'string', - format: 'binary', - description: 'The logo file to upload' - ), - ] - ) + schema: new OA\Schema(ref: '#/components/schemas/UploadSponsoredProjectLogoRequest') ) ), parameters: [ diff --git a/app/Swagger/SponsoredProjectSchemas.php b/app/Swagger/SponsoredProjectSchemas.php index 0d851e02b..79609b43e 100644 --- a/app/Swagger/SponsoredProjectSchemas.php +++ b/app/Swagger/SponsoredProjectSchemas.php @@ -64,3 +64,76 @@ class PaginatedProjectSponsorshipTypesResponseSchema {} )] class PaginatedSupportingCompaniesResponseSchema {} + + +#[OA\Schema( + schema: 'SponsoredProjectRequest', + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Project name'), + new OA\Property(property: 'description', type: 'string', description: 'Project description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the project is active'), + ] +)] +class SponsoredProjectRequestSchema {} + + +#[OA\Schema( + schema: 'ProjectSponsorshipTypeCreateRequest', + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), + new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] +)] +class ProjectSponsorshipTypeCreateRequestSchema {} + +#[OA\Schema( + schema: 'ProjectSponsorshipTypeUpdateRequest', + type: 'object', + properties: [ + new OA\Property(property: 'name', type: 'string', description: 'Sponsorship type name'), + new OA\Property(property: 'description', type: 'string', description: 'Sponsorship type description'), + new OA\Property(property: 'is_active', type: 'boolean', description: 'Whether the sponsorship type is active'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] +)] +class ProjectSponsorshipTypeUpdateRequestSchema {} + +#[OA\Schema( + schema: 'AddSupportingCompanyRequest', + type: 'object', + required: ['company_id'], + properties: [ + new OA\Property(property: 'company_id', type: 'integer', description: 'The company id'), + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] +)] +class AddSupportingCompanyRequestSchema {} + +#[OA\Schema( + schema: 'UpdateSupportingCompanyRequest', + type: 'object', + required: ['order'], + properties: [ + new OA\Property(property: 'order', type: 'integer', description: 'Display order'), + ] +)] +class UpdateSupportingCompanyRequestSchema {} + +#[OA\Schema( + schema: 'UploadSponsoredProjectLogoRequest', + type: 'object', + required: ['file'], + properties: [ + new OA\Property( + property: 'file', + type: 'string', + format: 'binary', + description: 'The logo file to upload' + ), + ] +)] +class UploadSponsoredProjectLogoRequestSchema {}