feat(api): block-playout history + sequential-schedule validation endpoints
Adds the REST surface for the #145 troubleshooting leftovers (#158 items 4-5): - GET /api/playouts/{id}/blocks - blocks a block playout schedules - GET /api/playouts/{id}/blocks/{blockId}/history - paged block history - GET /api/playouts/history/{id} - decode a history row by id - POST /api/troubleshoot/validate-schedule - validate sequential YAML New MediatR queries GetPlayoutHistoryDetails (Either, 404 unknown row / 422 malformed JSON) and ValidateSequentialSchedule (wraps ISequentialScheduleValidator, never throws). DecodePlayoutHistoryHandler and the new by-id handler now share PlayoutHistoryDecoder. Regenerated openapi/v1.json. Refs #145 #158 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -6315,6 +6315,251 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/{id}/blocks": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Get the blocks scheduled by a block playout",
|
||||
"description": "Lists the distinct blocks reachable through a Block playout's templates, ordered by group then name. A playout with no templates (including non-Block playouts) returns an empty list.",
|
||||
"operationId": "GetPlayoutBlocks",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/BlockResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/{id}/blocks/{blockId}/history": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Get a block's playout history",
|
||||
"description": "Returns the paged scheduling history for a single block within a block playout, oldest first. Each row's Key and Details carry raw JSON; decode a row via GET /api/playouts/history/{id}.",
|
||||
"operationId": "GetPlayoutBlockHistory",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blockId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pageNum",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pageSize",
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"default": 100
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PagedPlayoutHistoryResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/history/{id}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Playouts"
|
||||
],
|
||||
"summary": "Decode a playout history row",
|
||||
"description": "Decodes a single playout history row (by its id) into its playback order, collection, and media-item details. Returns 422 if the row's stored Key/Details JSON cannot be decoded.",
|
||||
"operationId": "GetPlayoutHistoryDetails",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryDetailsResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"404": {
|
||||
"description": "Not Found",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"422": {
|
||||
"description": "Unprocessable Entity",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/playouts/reset-all": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -10164,6 +10409,83 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/troubleshoot/validate-schedule": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Troubleshooting"
|
||||
],
|
||||
"summary": "Validate a sequential schedule YAML document",
|
||||
"description": "Validates a sequential-schedule YAML string against the full (or import) schema. Returns whether it is valid, any validation messages, and the JSON conversion of the YAML. Parse/validator errors are reported as messages (IsValid=false), never as a 500.",
|
||||
"operationId": "ValidateSequentialSchedule",
|
||||
"requestBody": {
|
||||
"content": {
|
||||
"application/json-patch+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
},
|
||||
"application/*+json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleRequest"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": true
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ValidateSequentialScheduleResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"content": {
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ProblemDetails"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/troubleshoot/playback.m3u8": {
|
||||
"head": {
|
||||
"tags": [
|
||||
@@ -15149,6 +15471,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PagedPlayoutHistoryResponseModel": {
|
||||
"required": [
|
||||
"totalCount",
|
||||
"page"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"totalCount": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"page": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/PlayoutHistoryResponseModel"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"PagedPlayoutItemsResponseModel": {
|
||||
"required": [
|
||||
"totalCount",
|
||||
@@ -15509,6 +15850,63 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutHistoryDetailsResponseModel": {
|
||||
"required": [
|
||||
"playbackOrder",
|
||||
"collectionType",
|
||||
"name",
|
||||
"mediaItemType",
|
||||
"mediaItemTitle"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"playbackOrder": {
|
||||
"$ref": "#/components/schemas/PlaybackOrder"
|
||||
},
|
||||
"collectionType": {
|
||||
"$ref": "#/components/schemas/CollectionType"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaItemType": {
|
||||
"type": "string"
|
||||
},
|
||||
"mediaItemTitle": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutHistoryResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
"when",
|
||||
"finish",
|
||||
"key",
|
||||
"details"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"when": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"finish": {
|
||||
"type": "string",
|
||||
"format": "date-time"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"details": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"PlayoutItemResponseModel": {
|
||||
"required": [
|
||||
"title",
|
||||
@@ -18276,6 +18674,46 @@
|
||||
],
|
||||
"type": "string"
|
||||
},
|
||||
"ValidateSequentialScheduleRequest": {
|
||||
"required": [
|
||||
"yaml",
|
||||
"isImport"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"yaml": {
|
||||
"type": [
|
||||
"null",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"isImport": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ValidateSequentialScheduleResponseModel": {
|
||||
"required": [
|
||||
"isValid",
|
||||
"messages",
|
||||
"json"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"isValid": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"messages": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"json": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"WatermarkFullResponseModel": {
|
||||
"required": [
|
||||
"id",
|
||||
|
||||
Reference in New Issue
Block a user