From 70fc6ef143278e7e37ec878469c4691ad407b791 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Mon, 20 Oct 2025 15:17:07 -0300 Subject: [PATCH 1/4] feat: Extend Swagger Coverage for controller `OAuth2SummitsTicketTypesApiController` --- .../OAuth2SummitsTicketTypesApiController.php | 344 +++++++++++++++++- app/Swagger/SummitRegistrationSchemas.php | 26 +- 2 files changed, 368 insertions(+), 2 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php index 962d7d1b3..90bcd310a 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php @@ -15,6 +15,7 @@ use App\ModelSerializers\SerializerUtils; use App\Rules\Boolean; use App\Services\Model\ISummitTicketTypeService; +use Illuminate\Http\Response; use Illuminate\Support\Facades\Log; use models\exceptions\ValidationException; use models\oauth2\IResourceServerContext; @@ -22,6 +23,7 @@ use models\summit\ISummitTicketTypeRepository; use models\summit\SummitTicketType; use ModelSerializers\SerializerRegistry; +use OpenApi\Attributes as OA; use utils\Filter; use utils\FilterElement; use utils\PagingInfo; @@ -74,6 +76,61 @@ public function __construct * @param $summit_id * @return mixed */ + #[OA\Get( + path: "/api/v1/summits/{id}/ticket-types", + summary: "Get all ticket types for a summit (public audience only)", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "page", + in: "query", + required: false, + schema: new OA\Schema(type: "integer", default: 1), + description: "Page number" + ), + new OA\Parameter( + name: "per_page", + in: "query", + required: false, + schema: new OA\Schema(type: "integer", default: 10), + description: "Items per page" + ), + new OA\Parameter( + name: "filter", + in: "query", + required: false, + explode: false, + schema: new OA\Schema(type: "string"), + description: "Filter operators: id==, badge_type_id==, name=@/@@/==, description=@/@@/==, external_id=@/@@/==, audience=@/@@/==, sales_start_date>/=/ ==/[], sales_end_date>/=/ ==/[], created>/=/ ==/[], last_edited>/=/ ==/[], allows_to_delegate==" + ), + new OA\Parameter( + name: "order", + in: "query", + required: false, + explode: false, + schema: new OA\Schema(type: "string"), + description: "Order by fields: id, created, name, external_id, audience" + ) + ], + responses: [ + new OA\Response( + response: 200, + description: "OK", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedSummitTicketTypesResponse") + ), + 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 getAllBySummit($summit_id) { @@ -225,6 +282,61 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { * @param $summit_id * @return mixed */ + #[OA\Get( + path: "/api/v2/summits/{id}/ticket-types", + summary: "Get all ticket types for a summit (all audiences)", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "page", + in: "query", + required: false, + schema: new OA\Schema(type: "integer", default: 1), + description: "Page number" + ), + new OA\Parameter( + name: "per_page", + in: "query", + required: false, + schema: new OA\Schema(type: "integer", default: 10), + description: "Items per page" + ), + new OA\Parameter( + name: "filter", + in: "query", + required: false, + explode: false, + schema: new OA\Schema(type: "string"), + description: "Filter operators: id==, badge_type_id==, name=@/@@/==, description=@/@@/==, external_id=@/@@/==, audience=@/@@/==, sales_start_date>/=/ ==/[], sales_end_date>/=/ ==/[], created>/=/ ==/[], last_edited>/=/ ==/[], allows_to_delegate==" + ), + new OA\Parameter( + name: "order", + in: "query", + required: false, + explode: false, + schema: new OA\Schema(type: "string"), + description: "Order by fields: id, created, name, external_id, audience" + ) + ], + responses: [ + new OA\Response( + response: 200, + description: "OK", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedSummitTicketTypesResponse") + ), + 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 getAllBySummitV2($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); @@ -288,6 +400,40 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { * @param $summit_id * @return mixed */ + #[OA\Get( + path: "/api/v1/summits/{id}/ticket-types/allowed", + summary: "Get allowed ticket types for current member", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "filter", + in: "query", + required: false, + explode: false, + schema: new OA\Schema(type: "string"), + description: "Filter operators: promo_code==" + ) + ], + responses: [ + new OA\Response( + response: 200, + description: "OK", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedSummitTicketTypesResponse") + ), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function getAllowedBySummitAndCurrentMember($summit_id) { return $this->processRequest(function () use ($summit_id) { @@ -336,6 +482,38 @@ public function getAllowedBySummitAndCurrentMember($summit_id) * @param $ticket_type_id * @return mixed */ + #[OA\Get( + path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + summary: "Get a specific ticket type by id", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "ticket_type_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The ticket type id" + ) + ], + responses: [ + new OA\Response( + response: 200, + description: "OK", + content: new OA\JsonContent(ref: "#/components/schemas/SummitTicketType") + ), + 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 getTicketTypeBySummit($summit_id, $ticket_type_id) { return $this->processRequest(function () use ($summit_id, $ticket_type_id) { @@ -357,6 +535,41 @@ public function getTicketTypeBySummit($summit_id, $ticket_type_id) * @param $summit_id * @return mixed */ + #[OA\Post( + path: "/api/v1/summits/{id}/ticket-types", + summary: "Create a new ticket type for a summit", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ) + ], + requestBody: new OA\RequestBody( + required: true, + content: new OA\MediaType( + mediaType: "application/json", + schema: new OA\Schema(ref: "#/components/schemas/SummitTicketType") + ) + ), + responses: [ + new OA\Response( + response: 201, + description: "Created", + content: new OA\JsonContent(ref: "#/components/schemas/SummitTicketType") + ), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function addTicketTypeBySummit($summit_id) { return $this->processRequest(function () use ($summit_id) { @@ -381,6 +594,48 @@ public function addTicketTypeBySummit($summit_id) * @param $ticket_type_id * @return mixed */ + #[OA\Put( + path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + summary: "Update a ticket type", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "ticket_type_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The ticket type id" + ) + ], + requestBody: new OA\RequestBody( + required: true, + content: new OA\MediaType( + mediaType: "application/json", + schema: new OA\Schema(ref: "#/components/schemas/SummitTicketType") + ) + ), + responses: [ + new OA\Response( + response: 200, + description: "OK", + content: new OA\JsonContent(ref: "#/components/schemas/SummitTicketType") + ), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function updateTicketTypeBySummit($summit_id, $ticket_type_id) { return $this->processRequest(function () use ($summit_id, $ticket_type_id) { @@ -405,6 +660,35 @@ public function updateTicketTypeBySummit($summit_id, $ticket_type_id) * @param $ticket_type_id * @return mixed */ + #[OA\Delete( + path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + summary: "Delete a ticket type", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "ticket_type_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The ticket type id" + ) + ], + responses: [ + new OA\Response(response: 204, description: "No Content"), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function deleteTicketTypeBySummit($summit_id, $ticket_type_id) { return $this->processRequest(function () use ($summit_id, $ticket_type_id) { @@ -422,6 +706,33 @@ public function deleteTicketTypeBySummit($summit_id, $ticket_type_id) * @param $summit_id * @return mixed */ + #[OA\Post( + path: "/api/v1/summits/{id}/ticket-types/seed-defaults", + summary: "Seed default ticket types from Eventbrite", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ) + ], + responses: [ + new OA\Response( + response: 201, + description: "Created", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedSummitTicketTypesResponse") + ), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function seedDefaultTicketTypesBySummit($summit_id) { return $this->processRequest(function () use ($summit_id) { @@ -453,6 +764,37 @@ public function seedDefaultTicketTypesBySummit($summit_id) * @param $currency_symbol * @return mixed */ + #[OA\Put( + path: "/api/v1/summits/{id}/ticket-types/all/currency/{currency_symbol}", + summary: "Update currency symbol for all ticket types in a summit", + security: [["Bearer" => []]], + tags: ["summit-ticket-types"], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer"), + description: "The summit id" + ), + new OA\Parameter( + name: "currency_symbol", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "The currency symbol (e.g., USD, EUR)" + ) + ], + responses: [ + new OA\Response(response: 200, description: "OK"), + 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: "Not Found"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error") + ] + )] public function updateCurrencySymbol($summit_id, $currency_symbol) { return $this->processRequest(function () use ($summit_id, $currency_symbol) { @@ -477,4 +819,4 @@ public function updateCurrencySymbol($summit_id, $currency_symbol) return $this->updated(); }); } -} \ No newline at end of file +} diff --git a/app/Swagger/SummitRegistrationSchemas.php b/app/Swagger/SummitRegistrationSchemas.php index b0c396f20..764ec5c04 100644 --- a/app/Swagger/SummitRegistrationSchemas.php +++ b/app/Swagger/SummitRegistrationSchemas.php @@ -38,6 +38,30 @@ class SummitTaxTypeCreateRequestSchema { } +// Summit Ticket Types + +#[OA\Schema( + schema: "PaginatedSummitTicketTypesResponse", + allOf: [ + new OA\Schema(ref: "#/components/schemas/PaginateDataSchemaResponse"), + new OA\Schema( + type: "object", + properties: [ + new OA\Property( + property: "data", + type: "array", + items: new OA\Items(ref: "#/components/schemas/SummitTicketType") + ) + ] + ) + ] +)] +class PaginatedSummitTicketTypesResponse +{ +} + +// Summit Badge Feature Types + #[OA\Schema( schema: 'SummitTaxTypeUpdateRequest', type: 'object', @@ -151,4 +175,4 @@ class SummitBadgeFeatureTypeCreateRequestSchema )] class SummitBadgeFeatureTypeUpdateRequestSchema { -} \ No newline at end of file +} From 937ccc136248e578c72348b4f4317a6a65130273 Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 27 Nov 2025 21:30:00 +0000 Subject: [PATCH 2/4] feat: Add SummitTaxType and update PaginatedSummitTicketTypesResponse schema --- app/Swagger/Models/SummitTicketTypeSchema.php | 53 ++++++++++--------- app/Swagger/SummitRegistrationSchemas.php | 2 +- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/app/Swagger/Models/SummitTicketTypeSchema.php b/app/Swagger/Models/SummitTicketTypeSchema.php index adff7042a..6d25531fd 100644 --- a/app/Swagger/Models/SummitTicketTypeSchema.php +++ b/app/Swagger/Models/SummitTicketTypeSchema.php @@ -4,39 +4,40 @@ use OpenApi\Attributes as OA; - #[OA\Schema( - schema: 'SummitTicketType', - type: 'object', + schema: "SummitTicketType", properties: [ new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'created', type: 'integer', example: 1), new OA\Property(property: 'last_edited', type: 'integer', example: 1), - new OA\Property(property: 'name', type: 'string'), - new OA\Property(property: 'description', type: 'string'), - new OA\Property(property: 'external_id', type: 'string'), - new OA\Property(property: 'summit_id', type: 'integer'), - new OA\Property(property: 'cost', type: 'float'), - new OA\Property(property: 'currency', type: 'string'), - new OA\Property(property: 'currency_symbol', type: 'string'), - new OA\Property(property: 'quantity_2_sell', type: 'integer'), - new OA\Property(property: 'max_quantity_per_order', type: 'integer'), - new OA\Property(property: 'sales_start_date', type: 'integer'), - new OA\Property(property: 'sales_end_date', type: 'integer'), - new OA\Property(property: 'badge_type_id', type: 'integer', description: 'SummitBadgeType ID, or add ?expand=badge_type for full object'), - new OA\Property(property: 'quantity_sold', type: 'integer'), - new OA\Property(property: 'audience', type: 'string'), - new OA\Property(property: 'allows_to_delegate', type: 'boolean'), - new OA\Property(property: 'allows_to_reassign', type: 'boolean'), + new OA\Property(property: "name", type: "string"), + new OA\Property(property: "description", type: "string"), + new OA\Property(property: "external_id", type: "string"), + new OA\Property(property: "summit_id", type: "integer"), + new OA\Property(property: "cost", type: "number", format: "float"), + new OA\Property(property: "currency", type: "string"), + new OA\Property(property: "currency_symbol", type: "string"), + new OA\Property(property: "quantity_2_sell", type: "integer"), + new OA\Property(property: "max_quantity_per_order", type: "integer"), + new OA\Property(property: "sales_start_date", type: "integer", description: "Unix timestamp"), + new OA\Property(property: "sales_end_date", type: "integer", description: "Unix timestamp"), + new OA\Property(property: "badge_type_id", type: "integer"), + new OA\Property(property: "quantity_sold", type: "integer"), + new OA\Property(property: "audience", type: "string", enum: ["All", "WithInvitation", "WithoutInvitation"]), + new OA\Property(property: "allows_to_delegate", type: "boolean"), + new OA\Property(property: "allows_to_reassign", type: "boolean"), + new OA\Property(property: "applied_taxes", type: "array", items: new OA\Items(oneOf: [ + new OA\Schema(type: 'integer'), + new OA\Schema(ref: '#/components/schemas/SummitTaxType') + ]), description: "Array of SummitTaxType IDs when in ?relations=applied_taxes, use ?expand=applied_taxes to get full objects"), + new OA\Property(property: "sub_type", type: "string", enum: ["Regular", "PrePaid"]), new OA\Property( - property: 'applied_taxes', - type: 'array', - items: new OA\Items(type: 'integer'), - example: [1, 2, 3], - description: 'Array of SummitTaxType IDs or its Model (only present when relations=applied_taxes), expanded when expand includes applied_taxes.' + property: "badge_type", + type: 'object', + description: "SummitBadgeType object when ?expand=badge_type" ), - new OA\Property(property: 'sub_type', type: 'string'), - ])] + ] +)] class SummitTicketTypeSchema { } diff --git a/app/Swagger/SummitRegistrationSchemas.php b/app/Swagger/SummitRegistrationSchemas.php index 764ec5c04..c43bf604f 100644 --- a/app/Swagger/SummitRegistrationSchemas.php +++ b/app/Swagger/SummitRegistrationSchemas.php @@ -56,7 +56,7 @@ class SummitTaxTypeCreateRequestSchema ) ] )] -class PaginatedSummitTicketTypesResponse +class PaginatedSummitTicketTypesResponseSchema { } From 41a8b5411b4022f5bb73f2c158fe14e8d94d292f Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Thu, 27 Nov 2025 21:55:01 +0000 Subject: [PATCH 3/4] feat: Enhance OpenAPI documentation for Summit Ticket Types API with OAuth2 security and request schemas --- .../OAuth2SummitsTicketTypesApiController.php | 158 +++++++++++------- .../Security/SummitTicketTypesAuthSchema.php | 31 ++++ app/Swagger/SummitRegistrationSchemas.php | 50 ++++++ 3 files changed, 175 insertions(+), 64 deletions(-) create mode 100644 app/Swagger/Security/SummitTicketTypesAuthSchema.php diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php index 90bcd310a..3d85d52ae 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php @@ -1,4 +1,5 @@ -repository = $repository; $this->summit_repository = $summit_repository; @@ -78,9 +81,10 @@ public function __construct */ #[OA\Get( path: "/api/v1/summits/{id}/ticket-types", + operationId: 'getAllTicketTypesBySummit', summary: "Get all ticket types for a summit (public audience only)", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::ReadSummitData, SummitScopes::ReadAllSummitData]]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -135,28 +139,29 @@ public function getAllBySummit($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); return $this->_getAll( function () { return [ - 'id' => [ '=='], + 'id' => ['=='], 'badge_type_id' => ['=='], 'name' => ['=@', '@@', '=='], 'description' => ['=@', '@@', '=='], 'external_id' => ['=@', '@@', '=='], 'audience' => ['=@', '@@', '=='], - 'sales_start_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'sales_end_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'created'=> ['>', '<', '<=', '>=', '==','[]'], - 'last_edited'=> ['>', '<', '<=', '>=', '==','[]'], + 'sales_start_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'sales_end_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'created' => ['>', '<', '<=', '>=', '==', '[]'], + 'last_edited' => ['>', '<', '<=', '>=', '==', '[]'], 'allows_to_delegate' => ['=='], ]; }, function () { return [ - 'id' =>'sometimes|integer', - 'badge_type_id' =>'sometimes|integer', + 'id' => 'sometimes|integer', + 'badge_type_id' => 'sometimes|integer', 'name' => 'sometimes|string', 'description' => 'sometimes|string', 'external_id' => 'sometimes|string', @@ -191,7 +196,8 @@ function () { function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { return $this->repository->getBySummit ( - $summit, new PagingInfo($page, $per_page), + $summit, + new PagingInfo($page, $per_page), call_user_func($applyExtraFilters, $filter), $order ); @@ -207,28 +213,29 @@ public function getAllBySummitCSV($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->getResourceServerContext())->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); return $this->_getAllCSV( function () { return [ - 'id' => [ '=='], + 'id' => ['=='], 'badge_type_id' => ['=='], 'name' => ['=@', '@@', '=='], 'description' => ['=@', '@@', '=='], 'external_id' => ['=@', '@@', '=='], 'audience' => ['=@', '@@', '=='], - 'sales_start_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'sales_end_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'created'=> ['>', '<', '<=', '>=', '==','[]'], - 'last_edited'=> ['>', '<', '<=', '>=', '==','[]'], + 'sales_start_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'sales_end_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'created' => ['>', '<', '<=', '>=', '==', '[]'], + 'last_edited' => ['>', '<', '<=', '>=', '==', '[]'], 'allows_to_delegate' => ['=='], ]; }, function () { return [ - 'id' =>'sometimes|integer', - 'badge_type_id' =>'sometimes|integer', + 'id' => 'sometimes|integer', + 'badge_type_id' => 'sometimes|integer', 'name' => 'sometimes|string', 'description' => 'sometimes|string', 'external_id' => 'sometimes|string', @@ -284,9 +291,11 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { */ #[OA\Get( path: "/api/v2/summits/{id}/ticket-types", + operationId: 'getAllTicketTypesBySummitV2', summary: "Get all ticket types for a summit (all audiences)", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::ReadSummitData, SummitScopes::ReadAllSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -340,27 +349,28 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { public function getAllBySummitV2($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); return $this->_getAll( function () { return [ - 'id' => [ '=='], + 'id' => ['=='], 'badge_type_id' => ['=='], 'name' => ['=@', '@@', '=='], 'description' => ['=@', '@@', '=='], 'external_id' => ['=@', '@@', '=='], 'audience' => ['=@', '@@', '=='], - 'sales_start_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'sales_end_date'=> ['>', '<', '<=', '>=', '==','[]'], - 'created'=> ['>', '<', '<=', '>=', '==','[]'], - 'last_edited'=> ['>', '<', '<=', '>=', '==','[]'], + 'sales_start_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'sales_end_date' => ['>', '<', '<=', '>=', '==', '[]'], + 'created' => ['>', '<', '<=', '>=', '==', '[]'], + 'last_edited' => ['>', '<', '<=', '>=', '==', '[]'], 'allows_to_delegate' => ['=='], ]; }, function () { return [ - 'id' =>'sometimes|integer', - 'badge_type_id' =>'sometimes|integer', + 'id' => 'sometimes|integer', + 'badge_type_id' => 'sometimes|integer', 'name' => 'sometimes|string', 'description' => 'sometimes|string', 'external_id' => 'sometimes|string', @@ -402,9 +412,10 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { */ #[OA\Get( path: "/api/v1/summits/{id}/ticket-types/allowed", + operationId: 'getAllowedTicketTypesBySummitAndCurrentMember', summary: "Get allowed ticket types for current member", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [MemberScopes::ReadMyMemberData]]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -438,17 +449,19 @@ public function getAllowedBySummitAndCurrentMember($summit_id) { return $this->processRequest(function () use ($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $member = $this->resource_server_context->getCurrentUser(); - if (is_null($member)) return $this->error403(); + if (is_null($member)) + return $this->error403(); - $filter = self::getFilter(function(){ + $filter = self::getFilter(function () { return [ 'promo_code' => ['=='], ]; - }, function(){ + }, function () { return [ 'promo_code' => 'sometimes|required|string', ]; @@ -484,9 +497,10 @@ public function getAllowedBySummitAndCurrentMember($summit_id) */ #[OA\Get( path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + operationId: 'getTicketTypeBySummit', summary: "Get a specific ticket type by id", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::ReadSummitData, SummitScopes::ReadAllSummitData]]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -518,7 +532,8 @@ public function getTicketTypeBySummit($summit_id, $ticket_type_id) { return $this->processRequest(function () use ($summit_id, $ticket_type_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $ticket_type = $summit->getTicketTypeById($ticket_type_id); if (is_null($ticket_type)) return $this->error404(); @@ -537,9 +552,11 @@ public function getTicketTypeBySummit($summit_id, $ticket_type_id) */ #[OA\Post( path: "/api/v1/summits/{id}/ticket-types", + operationId: 'addTicketTypeBySummit', summary: "Create a new ticket type for a summit", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -553,7 +570,7 @@ public function getTicketTypeBySummit($summit_id, $ticket_type_id) required: true, content: new OA\MediaType( mediaType: "application/json", - schema: new OA\Schema(ref: "#/components/schemas/SummitTicketType") + schema: new OA\Schema(ref: "#/components/schemas/SummitTicketTypeAddRequest") ) ), responses: [ @@ -575,7 +592,8 @@ public function addTicketTypeBySummit($summit_id) return $this->processRequest(function () use ($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $payload = $this->getJsonPayload(SummitTicketTypeValidationRulesFactory::buildForAdd()); @@ -596,9 +614,11 @@ public function addTicketTypeBySummit($summit_id) */ #[OA\Put( path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + operationId: 'updateTicketTypeBySummit', summary: "Update a ticket type", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -619,7 +639,7 @@ public function addTicketTypeBySummit($summit_id) required: true, content: new OA\MediaType( mediaType: "application/json", - schema: new OA\Schema(ref: "#/components/schemas/SummitTicketType") + schema: new OA\Schema(ref: "#/components/schemas/SummitTicketTypeUpdateRequest") ) ), responses: [ @@ -641,7 +661,8 @@ public function updateTicketTypeBySummit($summit_id, $ticket_type_id) return $this->processRequest(function () use ($summit_id, $ticket_type_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $payload = $this->getJsonPayload(SummitTicketTypeValidationRulesFactory::buildForUpdate()); @@ -662,9 +683,11 @@ public function updateTicketTypeBySummit($summit_id, $ticket_type_id) */ #[OA\Delete( path: "/api/v1/summits/{id}/ticket-types/{ticket_type_id}", + operationId: 'deleteTicketTypeBySummit', summary: "Delete a ticket type", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -694,7 +717,8 @@ public function deleteTicketTypeBySummit($summit_id, $ticket_type_id) return $this->processRequest(function () use ($summit_id, $ticket_type_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $this->ticket_type_service->deleteTicketType($summit, $ticket_type_id); @@ -708,9 +732,11 @@ public function deleteTicketTypeBySummit($summit_id, $ticket_type_id) */ #[OA\Post( path: "/api/v1/summits/{id}/ticket-types/seed-defaults", + operationId: 'seedDefaultTicketTypesBySummit', summary: "Seed default ticket types from Eventbrite", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -738,7 +764,8 @@ public function seedDefaultTicketTypesBySummit($summit_id) return $this->processRequest(function () use ($summit_id) { $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); + if (is_null($summit)) + return $this->error404(); $ticket_types = $this->ticket_type_service->seedSummitTicketTypesFromEventBrite($summit); @@ -766,9 +793,11 @@ public function seedDefaultTicketTypesBySummit($summit_id) */ #[OA\Put( path: "/api/v1/summits/{id}/ticket-types/all/currency/{currency_symbol}", + operationId: 'updateTicketTypesCurrencySymbol', summary: "Update currency symbol for all ticket types in a summit", - security: [["Bearer" => []]], - tags: ["summit-ticket-types"], + security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], + x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( name: "id", @@ -804,13 +833,14 @@ public function updateCurrencySymbol($summit_id, $currency_symbol) return $this->error404(); $member = $this->resource_server_context->getCurrentUser(); - if (is_null($member)) return $this->error403(); + if (is_null($member)) + return $this->error403(); - if(!$member->isAuthzFor($summit)){ + if (!$member->isAuthzFor($summit)) { return $this->error403(); } - if(!in_array($currency_symbol, SummitTicketType::AllowedCurrencies)){ + if (!in_array($currency_symbol, SummitTicketType::AllowedCurrencies)) { throw new ValidationException(sprintf("Currency symbol %s is not allowed.", $currency_symbol)); } @@ -819,4 +849,4 @@ public function updateCurrencySymbol($summit_id, $currency_symbol) return $this->updated(); }); } -} +} \ No newline at end of file diff --git a/app/Swagger/Security/SummitTicketTypesAuthSchema.php b/app/Swagger/Security/SummitTicketTypesAuthSchema.php new file mode 100644 index 000000000..380d26b18 --- /dev/null +++ b/app/Swagger/Security/SummitTicketTypesAuthSchema.php @@ -0,0 +1,31 @@ + 'Read Summit Data', + SummitScopes::ReadAllSummitData => 'Read All Summit Data', + SummitScopes::WriteSummitData => 'Write Summit Data', + SummitScopes::WriteTicketTypeData => 'Write Ticket Type Data', + MemberScopes::ReadMyMemberData => 'Read My Member Data', + ], + ), + ], +) +] +class SummitTicketTypesAuthSchema +{ +} \ No newline at end of file diff --git a/app/Swagger/SummitRegistrationSchemas.php b/app/Swagger/SummitRegistrationSchemas.php index c43bf604f..3d5042ecb 100644 --- a/app/Swagger/SummitRegistrationSchemas.php +++ b/app/Swagger/SummitRegistrationSchemas.php @@ -2,6 +2,7 @@ namespace App\Swagger\schemas; +use models\summit\SummitTicketType; use OpenApi\Attributes as OA; #[OA\Schema( @@ -62,6 +63,55 @@ class PaginatedSummitTicketTypesResponseSchema // Summit Badge Feature Types +#[OA\Schema( + schema: "SummitTicketTypeAddRequest", + type: "object", + required: ["name"], + properties: [ + new OA\Property(property: "name", type: "string", example: "General Admission"), + new OA\Property(property: "description", type: "string", example: "Standard ticket for conference access"), + new OA\Property(property: "external_id", type: "string", maxLength: 255, example: "ext-123"), + new OA\Property(property: "cost", type: "number", format: "float", minimum: 0, example: 99.99), + new OA\Property(property: "currency", type: "string", description: "Required when cost is provided. ISO currency code.", example: "USD"), + new OA\Property(property: "quantity_2_sell", type: "integer", minimum: 0, example: 100), + new OA\Property(property: "max_quantity_per_order", type: "integer", minimum: 0, example: 10), + new OA\Property(property: "sales_start_date", type: "integer", description: "Unix timestamp", example: 1640995200, nullable: true), + new OA\Property(property: "sales_end_date", type: "integer", description: "Unix timestamp (must be after sales_start_date)", example: 1641081600, nullable: true), + new OA\Property(property: "badge_type_id", type: "integer", example: 1), + new OA\Property(property: "audience", type: "string", enum: SummitTicketType::AllowedAudience, example: SummitTicketType::Audience_All), + new OA\Property(property: "allows_to_delegate", type: "boolean", example: true), + new OA\Property(property: "allows_to_reassign", type: "boolean", example: true), + ] +)] +class SummitTicketTypeAddRequestSchema +{ +} + +#[OA\Schema( + schema: "SummitTicketTypeUpdateRequest", + type: "object", + properties: [ + new OA\Property(property: "name", type: "string", example: "General Admission"), + new OA\Property(property: "description", type: "string", example: "Standard ticket for conference access"), + new OA\Property(property: "external_id", type: "string", maxLength: 255, example: "ext-123"), + new OA\Property(property: "cost", type: "number", format: "float", minimum: 0, example: 99.99), + new OA\Property(property: "currency", type: "string", description: "ISO currency code", example: "USD"), + new OA\Property(property: "quantity_2_sell", type: "integer", minimum: 0, example: 100), + new OA\Property(property: "max_quantity_per_order", type: "integer", minimum: 0, example: 10), + new OA\Property(property: "sales_start_date", type: "integer", description: "Unix timestamp", example: 1640995200, nullable: true), + new OA\Property(property: "sales_end_date", type: "integer", description: "Unix timestamp (must be after sales_start_date)", example: 1641081600, nullable: true), + new OA\Property(property: "badge_type_id", type: "integer", example: 1), + new OA\Property(property: "audience", type: "string", enum: SummitTicketType::AllowedAudience, example: SummitTicketType::Audience_All), + new OA\Property(property: "allows_to_delegate", type: "boolean", example: true), + new OA\Property(property: "allows_to_reassign", type: "boolean", example: true), + ] +)] +class SummitTicketTypeUpdateRequestSchema +{ +} + +// Summit Badge Feature Types + #[OA\Schema( schema: 'SummitTaxTypeUpdateRequest', type: 'object', From 8d284a93a32da1994a9a1aa9e191a656931a663e Mon Sep 17 00:00:00 2001 From: Matias Perrone Date: Wed, 3 Dec 2025 20:09:58 +0000 Subject: [PATCH 4/4] feat: Add changes requested --- .../OAuth2SummitsTicketTypesApiController.php | 14 +++++++------- .../Security/SummitTicketTypesAuthSchema.php | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php index 3d85d52ae..9aafa9c4e 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitsTicketTypesApiController.php @@ -294,7 +294,7 @@ function ($page, $per_page, $filter, $order, $applyExtraFilters) use ($summit) { operationId: 'getAllTicketTypesBySummitV2', summary: "Get all ticket types for a summit (all audiences)", security: [["summit_ticket_types_oauth2" => [SummitScopes::ReadSummitData, SummitScopes::ReadAllSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -555,7 +555,7 @@ public function getTicketTypeBySummit($summit_id, $ticket_type_id) operationId: 'addTicketTypeBySummit', summary: "Create a new ticket type for a summit", security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -617,7 +617,7 @@ public function addTicketTypeBySummit($summit_id) operationId: 'updateTicketTypeBySummit', summary: "Update a ticket type", security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -686,7 +686,7 @@ public function updateTicketTypeBySummit($summit_id, $ticket_type_id) operationId: 'deleteTicketTypeBySummit', summary: "Delete a ticket type", security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -735,7 +735,7 @@ public function deleteTicketTypeBySummit($summit_id, $ticket_type_id) operationId: 'seedDefaultTicketTypesBySummit', summary: "Seed default ticket types from Eventbrite", security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -796,7 +796,7 @@ public function seedDefaultTicketTypesBySummit($summit_id) operationId: 'updateTicketTypesCurrencySymbol', summary: "Update currency symbol for all ticket types in a summit", security: [["summit_ticket_types_oauth2" => [SummitScopes::WriteTicketTypeData, SummitScopes::WriteSummitData]]], - x: ["authz_groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], + x: ["required-groups" => [IGroup::SuperAdmins, IGroup::Administrators, IGroup::SummitAdministrators, IGroup::SummitRegistrationAdmins]], tags: ["Summit Ticket Types"], parameters: [ new OA\Parameter( @@ -849,4 +849,4 @@ public function updateCurrencySymbol($summit_id, $currency_symbol) return $this->updated(); }); } -} \ No newline at end of file +} diff --git a/app/Swagger/Security/SummitTicketTypesAuthSchema.php b/app/Swagger/Security/SummitTicketTypesAuthSchema.php index 380d26b18..db868e3bd 100644 --- a/app/Swagger/Security/SummitTicketTypesAuthSchema.php +++ b/app/Swagger/Security/SummitTicketTypesAuthSchema.php @@ -1,6 +1,6 @@