diff --git a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTrackTagGroupsApiController.php b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTrackTagGroupsApiController.php index 295690865..25d83f024 100644 --- a/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTrackTagGroupsApiController.php +++ b/app/Http/Controllers/Apis/Protected/Summit/OAuth2SummitTrackTagGroupsApiController.php @@ -11,7 +11,9 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ +use App\Models\Foundation\Main\IGroup; use App\Models\Foundation\Summit\Repositories\ITrackTagGroupAllowedTagsRepository; +use App\Security\SummitScopes; use App\Services\Model\ISummitTrackTagGroupService; use libs\utils\PaginationValidationRules; use models\oauth2\IResourceServerContext; @@ -28,6 +30,8 @@ use models\exceptions\ValidationException; use models\summit\ISummitRepository; use utils\PagingResponse; +use OpenApi\Attributes as OA; +use Symfony\Component\HttpFoundation\Response; /** * Class OAuth2SummitTrackTagGroupsApiController @@ -67,6 +71,40 @@ public function __construct $this->repository = $repository; } + #[OA\Get( + path: "/api/v1/summits/{id}/track-tag-groups", + operationId: "getTrackTagGroupsBySummit", + description: "Get all track tag groups for a summit", + tags: ["Track Tag Groups"], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::ReadAllSummitData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "expand", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Expand relationships: allowed_tags" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Track tag groups retrieved successfully", + content: new OA\JsonContent(ref: "#/components/schemas/TrackTagGroupsList") + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @return mixed @@ -109,6 +147,92 @@ public function getTrackTagGroupsBySummit($summit_id){ } } + #[OA\Get( + path: "/api/v1/summits/{id}/track-tag-groups/all/allowed-tags", + operationId: "getAllowedTags", + description: "Get all allowed tags for track tag groups in a summit. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "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: 5), + description: "Items per page" + ), + new OA\Parameter( + name: "filter", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Filters, allowed operands: == (equals), =@ (contains), @@ (full text search), allowed fields: tag", + example: "tag==AI", + ), + new OA\Parameter( + name: "order", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Order by: tag, id" + ), + new OA\Parameter( + name: "expand", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Expand relationships allowed values: track_tag_group, tag" + ), + new OA\Parameter( + name: "fields", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Specific fields to return" + ), + new OA\Parameter( + name: "relations", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Relations to include" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Allowed tags retrieved successfully", + content: new OA\JsonContent(ref: "#/components/schemas/PaginatedTrackTagGroupAllowedTagsResponse") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @return mixed @@ -197,6 +321,47 @@ public function getAllowedTags($summit_id){ } } + #[OA\Post( + path: "/api/v1/summits/{id}/track-tag-groups", + operationId: "addTrackTagGroup", + description: "Create a new track tag group. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTrackTagGroupsData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + ], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent(ref: "#/components/schemas/CreateTrackTagGroupRequest") + ), + responses: [ + new OA\Response( + response: Response::HTTP_CREATED, + description: "Track tag group created successfully", + content: new OA\JsonContent(ref: "#/components/schemas/TrackTagGroup") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @return mixed @@ -247,6 +412,133 @@ public function addTrackTagGroup($summit_id){ } } + #[OA\Get( + path: "/api/v1/summits/{id}/track-tag-groups/{track_tag_group_id}", + operationId: "getTrackTagGroup", + description: "Get a specific track tag group. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::ReadAllSummitData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "track_tag_group_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Track tag group ID" + ), + new OA\Parameter( + name: "expand", + in: "query", + required: false, + schema: new OA\Schema(type: "string"), + description: "Expand relationships: allowed_tags" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Track tag group retrieved successfully", + content: new OA\JsonContent(ref: "#/components/schemas/TrackTagGroup") + ), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Track tag group or summit 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"), + ] + )] + /** + * @param $summit_id + * @param $track_tag_group_id + * @return mixed + */ + public function getTrackTagGroup($summit_id, $track_tag_group_id){ + try{ + $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); + if (is_null($summit)) return $this->error404(); + $track_tag_group = $summit->getTrackTagGroup(intval($track_tag_group_id)); + if(is_null($track_tag_group)) + return $this->error404(); + + return $this->ok(SerializerRegistry::getInstance()->getSerializer($track_tag_group)->serialize(Request::input('expand', ''))); + } + catch (ValidationException $ex1) { + Log::warning($ex1); + return $this->error412([$ex1->getMessage()]); + } + catch(EntityNotFoundException $ex2) + { + Log::warning($ex2); + return $this->error404(['message'=> $ex2->getMessage()]); + } + catch (\Exception $ex) { + Log::error($ex); + return $this->error500($ex); + } + } + + #[OA\Put( + path: "/api/v1/summits/{id}/track-tag-groups/{track_tag_group_id}", + operationId: "updateTrackTagGroup", + description: "Update an existing track tag group. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTrackTagGroupsData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "track_tag_group_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Track tag group ID" + ), + ], + requestBody: new OA\RequestBody( + required: true, + content: new OA\JsonContent(ref: "#/components/schemas/UpdateTrackTagGroupRequest") + ), + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Track tag group updated successfully", + content: new OA\JsonContent(ref: "#/components/schemas/TrackTagGroup") + ), + new OA\Response(response: Response::HTTP_BAD_REQUEST, description: "Bad Request"), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Track tag group or summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @param $track_tag_group_id @@ -304,36 +596,48 @@ public function updateTrackTagGroup($summit_id, $track_tag_group_id){ } } - /** - * @param $summit_id - * @param $track_tag_group_id - * @return mixed - */ - public function getTrackTagGroup($summit_id, $track_tag_group_id){ - try{ - $summit = SummitFinderStrategyFactory::build($this->summit_repository, $this->resource_server_context)->find($summit_id); - if (is_null($summit)) return $this->error404(); - $track_tag_group = $summit->getTrackTagGroup(intval($track_tag_group_id)); - if(is_null($track_tag_group)) - return $this->error404(); - - return $this->ok(SerializerRegistry::getInstance()->getSerializer($track_tag_group)->serialize(Request::input('expand', ''))); - } - catch (ValidationException $ex1) { - Log::warning($ex1); - return $this->error412([$ex1->getMessage()]); - } - catch(EntityNotFoundException $ex2) - { - Log::warning($ex2); - return $this->error404(['message'=> $ex2->getMessage()]); - } - catch (\Exception $ex) { - Log::error($ex); - return $this->error500($ex); - } - } - + #[OA\Delete( + path: "/api/v1/summits/{id}/track-tag-groups/{track_tag_group_id}", + operationId: "deleteTrackTagGroup", + description: "Delete a track tag group. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTrackTagGroupsData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "track_tag_group_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Track tag group ID" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_NO_CONTENT, + description: "Track tag group deleted successfully" + ), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Track tag group or summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @param $track_tag_group_id @@ -364,6 +668,42 @@ public function deleteTrackTagGroup($summit_id, $track_tag_group_id){ } } + #[OA\Post( + path: "/api/v1/summits/{id}/track-tag-groups/seed-defaults", + operationId: "seedDefaultTrackTagGroups", + description: "Seed default track tag groups for a summit. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTrackTagGroupsData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_CREATED, + description: "Default track tag groups seeded successfully", + content: new OA\JsonContent(ref: "#/components/schemas/TrackTagGroupsList") + ), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @return mixed @@ -400,6 +740,48 @@ public function seedDefaultTrackTagGroups($summit_id){ } } + #[OA\Post( + path: "/api/v1/summits/{id}/track-tag-groups/all/allowed-tags/{tag_id}/seed-on-tracks", + operationId: "seedTagOnAllTracks", + description: "Seed a tag on all tracks in a summit. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTracksData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "tag_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Tag ID" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Tag seeded successfully on all tracks" + ), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit or tag not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @param $tag_id @@ -427,6 +809,55 @@ public function seedTagOnAllTracks($summit_id, $tag_id){ } } + #[OA\Post( + path: "/api/v1/summits/{id}/track-tag-groups/{track_tag_group_id}/allowed-tags/all/copy/tracks/{track_id}", + operationId: "seedTagTrackGroupOnTrack", + description: "Seed a track tag group on a specific track. required-groups " . IGroup::SuperAdmins . ", " . IGroup::Administrators . ", " . IGroup::SummitAdministrators, + tags: ["Track Tag Groups"], + x: [ + 'required-groups' => [ + IGroup::SuperAdmins, + IGroup::Administrators, + IGroup::SummitAdministrators, + ] + ], + security: [['summit_track_tag_groups_oauth2' => [ + SummitScopes::WriteSummitData, + SummitScopes::WriteTracksData, + ]]], + parameters: [ + new OA\Parameter( + name: "id", + in: "path", + required: true, + schema: new OA\Schema(type: "string"), + description: "Summit ID" + ), + new OA\Parameter( + name: "track_tag_group_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Track tag group ID" + ), + new OA\Parameter( + name: "track_id", + in: "path", + required: true, + schema: new OA\Schema(type: "integer", format: "int64"), + description: "Track ID" + ), + ], + responses: [ + new OA\Response( + response: Response::HTTP_OK, + description: "Track tag group seeded successfully on track" + ), + new OA\Response(response: Response::HTTP_PRECONDITION_FAILED, description: "Validation Error"), + new OA\Response(response: Response::HTTP_NOT_FOUND, description: "Summit, track or track tag group not found"), + new OA\Response(response: Response::HTTP_INTERNAL_SERVER_ERROR, description: "Server Error"), + ] + )] /** * @param $summit_id * @param $track_tag_group_id @@ -454,4 +885,4 @@ public function seedTagTrackGroupOnTrack($summit_id, $track_tag_group_id, $track return $this->error500($ex); } } -} \ No newline at end of file +} diff --git a/app/Swagger/Models/TagSchema.php b/app/Swagger/Models/TagSchema.php new file mode 100644 index 000000000..3166becf0 --- /dev/null +++ b/app/Swagger/Models/TagSchema.php @@ -0,0 +1,27 @@ + 'Read All Summit Data', + SummitScopes::WriteSummitData => 'Write Summit Data', + SummitScopes::WriteTrackTagGroupsData => 'Write Track Tag Groups Data', + SummitScopes::WriteTracksData => 'Write Tracks Data', + ], + ), + ], + ) +] +class SummitTrackTagGroupsAuthSchema{} diff --git a/app/Swagger/SummitTrackTagGroupsSchemas.php b/app/Swagger/SummitTrackTagGroupsSchemas.php index 6b3e2f895..99856be0c 100644 --- a/app/Swagger/SummitTrackTagGroupsSchemas.php +++ b/app/Swagger/SummitTrackTagGroupsSchemas.php @@ -4,4 +4,248 @@ use OpenApi\Attributes as OA; -// +#[OA\Schema( + schema: "PaginatedTrackTagGroupAllowedTagsResponse", + type: "object", + properties: [ + new OA\Property( + property: "data", + type: "array", + items: new OA\Items(ref: "#/components/schemas/TrackTagGroupAllowedTag") + ), + new OA\Property( + property: "total", + type: "integer", + example: 15 + ), + new OA\Property( + property: "per_page", + type: "integer", + example: 5 + ), + new OA\Property( + property: "current_page", + type: "integer", + example: 1 + ), + ] +)] +class PaginatedTrackTagGroupAllowedTagsResponseSchema {} + +#[OA\Schema( + schema: "TrackTagGroup", + type: "object", + required: ["id", "name", "label", "is_mandatory", "summit_id"], + 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", maxLength: 50, description: "Track tag group name", example: "Difficulty Level"), + new OA\Property(property: "label", type: "string", maxLength: 50, description: "Display label for the tag group", example: "Difficulty"), + new OA\Property(property: "is_mandatory", type: "boolean", description: "Whether this tag group is mandatory", example: false), + new OA\Property(property: "order", type: "integer", description: "Display order of the tag group", example: 1), + new OA\Property(property: "summit_id", type: "integer", format: "int64", description: "Summit ID this tag group belongs to", example: 1), + new OA\Property( + property: "allowed_tags", type: "array", description: "Array of allowed tag IDs. Use expand=allowed_tags to get full TrackTagGroupAllowedTag objects", items: new OA\Items( + oneOf: [ + new OA\Schema(type: "integer", format: "int64", example: 1), + new OA\Schema(ref: "#/components/schemas/TrackTagGroupAllowedTag") + ] + ), + ), + ] +)] +class TrackTagGroupSchema {} + +// TrackTagGroupAllowedTag schema +#[OA\Schema( + schema: "TrackTagGroupAllowedTag", + type: "object", + required: ["id", "tag_id", "track_tag_group_id"], + properties: [ + new OA\Property( + property: "id", + type: "integer", + format: "int64", + description: "Allowed tag ID", + example: 1 + ), + new OA\Property( + property: "tag_id", + type: "integer", + format: "int64", + description: "Tag ID", + example: 1 + ), + new OA\Property( + property: "track_tag_group_id", + type: "integer", + format: "int64", + description: "Track tag group ID", + example: 1 + ), + new OA\Property( + property: "summit_id", + type: "integer", + format: "int64", + description: "Summit ID", + example: 1 + ), + new OA\Property( + property: "is_default", + type: "boolean", + description: "Whether this tag is the default for the group", + example: false + ), + new OA\Property( + property: "tag", + type: "object", + description: "Tag object (when expanded=tag)", + ref: "#/components/schemas/Tag" + ), + new OA\Property( + property: "track_tag_group", + type: "object", + description: "Track tag group object (when expanded=track_tag_group)", + ref: "#/components/schemas/TrackTagGroup" + ), + ] +)] +class TrackTagGroupAllowedTagSchema {} + +// TrackTagGroupsList schema +#[OA\Schema( + schema: "TrackTagGroupsList", + 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/TrackTagGroup") + ), + ]), + ] +)] +class TrackTagGroupsListSchema {} + +// PaginatedTrackTagGroupResponse schema +#[OA\Schema( + schema: "PaginatedTrackTagGroupResponse", + type: "object", + properties: [ + new OA\Property( + property: "data", + type: "array", + items: new OA\Items(ref: "#/components/schemas/TrackTagGroup") + ), + new OA\Property( + property: "total", + type: "integer", + example: 15 + ), + new OA\Property( + property: "per_page", + type: "integer", + example: 5 + ), + new OA\Property( + property: "current_page", + type: "integer", + example: 1 + ), + new OA\Property( + property: "last_page", + type: "integer", + example: 3 + ), + new OA\Property( + property: "from", + type: "integer", + example: 1 + ), + new OA\Property( + property: "to", + type: "integer", + example: 5 + ), + ] +)] +class PaginatedTrackTagGroupResponseSchema {} + +// CreateTrackTagGroupRequest schema +#[OA\Schema( + schema: "CreateTrackTagGroupRequest", + type: "object", + required: ["name", "label", "is_mandatory"], + properties: [ + new OA\Property( + property: "name", + type: "string", + maxLength: 50, + description: "Track tag group name", + example: "Difficulty Level" + ), + new OA\Property( + property: "label", + type: "string", + maxLength: 50, + description: "Display label", + example: "Difficulty" + ), + new OA\Property( + property: "is_mandatory", + type: "boolean", + description: "Whether this group is mandatory", + example: false + ), + new OA\Property( + property: "allowed_tags", + type: "array", + description: "Tag IDs to include in this group", + items: new OA\Items(type: "integer", format: "int64"), + example: [1, 2, 3] + ), + ] +)] +class CreateTrackTagGroupRequestSchema {} + +// UpdateTrackTagGroupRequest schema +#[OA\Schema( + schema: "UpdateTrackTagGroupRequest", + type: "object", + properties: [ + new OA\Property( + property: "name", + type: "string", + maxLength: 50, + description: "Track tag group name" + ), + new OA\Property( + property: "label", + type: "string", + maxLength: 50, + description: "Display label" + ), + new OA\Property( + property: "is_mandatory", + type: "boolean", + description: "Whether this group is mandatory" + ), + new OA\Property( + property: "order", + type: "integer", + minimum: 1, + description: "Display order" + ), + new OA\Property( + property: "allowed_tags", + type: "array", + description: "Tag IDs to include", + items: new OA\Items(type: "integer", format: "int64") + ), + ] +)] +class UpdateTrackTagGroupRequestSchema {}