From 9a1ddec71a419da8809b77d43a85917dc182af25 Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 11 Jul 2026 16:52:05 +0200 Subject: [PATCH] fix(202): make RemoteLibrariesEditScreen reviewable (NUL delimiter -> \u0000 escape) + Plex library-prefs missing-id 422 guard (review) --- .../PlexMediaSourcesControllerTests.cs | 21 ++++++++++++++++++ .../Api/PlexMediaSourcesController.cs | 12 ++++++++++ web/src/screens/RemoteLibrariesEditScreen.tsx | Bin 9767 -> 9772 bytes 3 files changed, 33 insertions(+) diff --git a/ErsatzTV.Tests/Controllers/PlexMediaSourcesControllerTests.cs b/ErsatzTV.Tests/Controllers/PlexMediaSourcesControllerTests.cs index 6b7431d15..4c66dacd1 100644 --- a/ErsatzTV.Tests/Controllers/PlexMediaSourcesControllerTests.cs +++ b/ErsatzTV.Tests/Controllers/PlexMediaSourcesControllerTests.cs @@ -259,6 +259,27 @@ public class PlexMediaSourcesControllerTests await _mediator.DidNotReceive().Send(Arg.Any(), Arg.Any()); } + [Test] + public async Task ReplaceLibraries_Should_Return_422_When_An_Owned_Library_Is_Missing() + { + SourceExists(true); + _mediator.Send(Arg.Any(), Arg.Any()) + .Returns(new List + { + new(5, "Movies", LibraryMediaKind.Movies, true), + new(6, "Shows", LibraryMediaKind.Shows, true) + }); + + // request omits owned id 6 -> 422: the PUT is a complete flag document (§C4a), matching Jellyfin/Emby + IActionResult result = await _controller.ReplaceLibraryPreferences( + 3, + new ReplaceRemoteLibraryPreferencesRequest([new RemoteLibraryPreferenceRequest(5, true)]), + CancellationToken.None); + + result.ShouldBeOfType(); + await _mediator.DidNotReceive().Send(Arg.Any(), Arg.Any()); + } + [Test] public async Task ReplaceLibraries_Should_Save_Enqueue_Ordered_Pair_And_Return_Reloaded() { diff --git a/ErsatzTV/Controllers/Api/PlexMediaSourcesController.cs b/ErsatzTV/Controllers/Api/PlexMediaSourcesController.cs index c47d61e6f..e1cc451d6 100644 --- a/ErsatzTV/Controllers/Api/PlexMediaSourcesController.cs +++ b/ErsatzTV/Controllers/Api/PlexMediaSourcesController.cs @@ -164,6 +164,18 @@ public class PlexMediaSourcesController( .ToErrorResult(); } + // Require the complete set of this source's libraries (§C4a; matches Jellyfin/Emby): the PUT is a + // full flag document, so an omitted owned id would silently keep its old sync state. + var incomingIds = libraries.Map(l => l.Id).ToList(); + var missingIds = ownedIds.Where(ownedId => !incomingIds.Contains(ownedId)).ToList(); + if (missingIds.Count > 0) + { + return BaseError.New( + $"The request must include every library for Plex media source {id} " + + $"(missing id(s) {string.Join(", ", missingIds)})") + .ToErrorResult(); + } + Either result = await mediator.Send(request.ToPlexCommand(), cancellationToken); if (result.IsLeft) diff --git a/web/src/screens/RemoteLibrariesEditScreen.tsx b/web/src/screens/RemoteLibrariesEditScreen.tsx index 8e304f1dfe4c8fef04b10e6822b6330525e78f7d..ead8afbbc61a3c677895e8a80aa1c2c1c602a117 100644 GIT binary patch delta 19 ZcmZ4Pv&Lsb94lK)sR0mdj%Pig002hW29*E+ delta 14 VcmZ4Ev)pGx94jNk<`mWw3IHjU1q1*9