diff --git a/ErsatzTV/Controllers/Api/PlayoutController.cs b/ErsatzTV/Controllers/Api/PlayoutController.cs index 27b9f8f99..eeb29ff4c 100644 --- a/ErsatzTV/Controllers/Api/PlayoutController.cs +++ b/ErsatzTV/Controllers/Api/PlayoutController.cs @@ -148,25 +148,28 @@ public class PlayoutController(IMediator mediator) : ControllerBase } } + // the schedule-file update is the only step that can fail after the pre-checks, + // so it goes first — a rejected file must not leave DailyRebuildTime applied + if (hasScheduleFile) + { + foreach (PlayoutNameViewModel playout in maybePlayout) + { + Either scheduleFileResult = + await UpdateScheduleFile(playout, request.ScheduleFile, cancellationToken); + foreach (BaseError error in scheduleFileResult.LeftToSeq()) + { + return error.ToErrorResult(); + } + } + } + Option dailyRebuildTime = request.DailyRebuildTime is { } t ? Some(t) : Option.None; Either result = await mediator.Send(new UpdatePlayout(id, dailyRebuildTime), cancellationToken); - return await result.Match( - Left: error => Task.FromResult(error.ToErrorResult()), - Right: async playout => - { - if (!hasScheduleFile) - { - return (IActionResult)new OkObjectResult(ToResponse(playout)); - } - - Either scheduleFileResult = - await UpdateScheduleFile(playout, request.ScheduleFile, cancellationToken); - return scheduleFileResult.Match( - Left: error => error.ToErrorResult(), - Right: updated => (IActionResult)new OkObjectResult(ToResponse(updated))); - }); + return result.Match( + Left: error => error.ToErrorResult(), + Right: playout => (IActionResult)new OkObjectResult(ToResponse(playout))); } private async Task> UpdateScheduleFile(