Adds LocalLibrariesController (L1-L7: list/get/create/update/delete/move-path/ path-exists) wrapping the existing local-library MediatR commands, mapping to the shared S0 response DTOs. Per design #202 §A.1/§C5/§C6: - 404 for L4/L5/L6 comes from a controller pre-check (GetLocalLibraryById is None), not the handler -- .Apply/.ToEitherAsync both .Join() a NotFoundError into a plain 422, so relying on the handler would be dead code. This is check-then-act; a delete racing the pre-check falls through to the handler's 422, documented in the controller. - L4/L5 409 via IEntityLocker.IsLibraryLocked(id); L6 resolves the source library from the path id (new ILibraryRepository.GetLibraryIdForPath) before its own lock check. - MoveLocalLibraryPathHandler gains same-MediaKind and different-library validation (finding 3) -- Blazor only filtered these client-side in the move dialog, so an API/MCP client could bypass them. - CreateLocalLibraryHandler/UpdateLocalLibraryHandler gain a shared NewPathsMustExist validation (LocalLibraryHandlerBase) that Directory.Exists- checks only new paths (Id < 1); existing rows stay exempt so an unmounted share doesn't block a rename. L7 (path-exists) is a controller-local IFileSystem check with no command. Tests: controller route/mediator-arg tests incl. 404-pre-check vs fall-through-422 and 409-lock cases; handler tests for the move-path cross-kind/same-library 422s, new-path 422 (missing/mixed), and a lossless round-trip proving local paths are identified by normalized path string, not id. Full solution test suite (Scanner/Core/Architecture/Tests/Infrastructure) green, 0 regressions. Deviations: none from the S1 slice description. Did not touch MediaSourceRepository.cs or any Plex/Jellyfin/Emby file (S2/S3 scope). Did not run the OpenAPI regen scripts (separate gate after S1-S3 merge per design §E).
30 lines
1.4 KiB
C#
30 lines
1.4 KiB
C#
using ErsatzTV.Core.Domain;
|
|
|
|
namespace ErsatzTV.Core.Interfaces.Repositories;
|
|
|
|
public interface ILibraryRepository
|
|
{
|
|
Task<LibraryPath> Add(LibraryPath libraryPath);
|
|
Task<Option<Library>> GetLibrary(int libraryId);
|
|
Task<Option<LocalLibrary>> GetLocal(int libraryId);
|
|
|
|
/// <summary>
|
|
/// Resolves the owning library id for a library path, without loading the full entity graph.
|
|
/// Used by the local-libraries API to pre-check a path's existence/ownership before a move
|
|
/// (see design #202 §C6 — the 404/lock-check for <c>POST .../paths/{pathId}/move</c>).
|
|
/// </summary>
|
|
Task<Option<int>> GetLibraryIdForPath(int libraryPathId);
|
|
|
|
Task<List<Library>> GetAll();
|
|
Task<Unit> UpdateLastScan(Library library);
|
|
Task<Unit> UpdateLastScan(LibraryPath libraryPath);
|
|
Task<List<LibraryPath>> GetLocalPaths(int libraryId);
|
|
Task<int> CountMediaItemsByPath(int libraryPathId);
|
|
Task SetEtag(LibraryPath libraryPath, Option<LibraryFolder> knownFolder, string path, string etag);
|
|
Task CleanEtagsForLibraryPath(LibraryPath libraryPath);
|
|
Task<Option<int>> GetParentFolderId(LibraryPath libraryPath, string folder, CancellationToken cancellationToken);
|
|
Task<LibraryFolder> GetOrAddFolder(LibraryPath libraryPath, Option<int> maybeParentFolder, string folder);
|
|
Task UpdateLibraryFolderId(MediaFile mediaFile, int libraryFolderId);
|
|
Task UpdatePath(LibraryPath libraryPath, string normalizedLibraryPath);
|
|
}
|