Enforce per-medium track cardinality in the upload service via MediumRules
Promote the Session/Mix single-track rule from a CMS-form convention to a domain invariant: declare cardinality as data in MediumRules, enforce it in UnifiedTrackService before the vault write (no orphan), return 409, and read the same rule in the batch-form collapse.
This commit is contained in:
@@ -36,6 +36,15 @@ public interface ITrackService
|
||||
Task<ResultContainer<ReleaseDto>> FindOrCreateRelease(
|
||||
string title, string artist, ReleaseDto releaseData, CancellationToken cancellationToken = default);
|
||||
|
||||
/// <summary>
|
||||
/// Read-only peek for an existing release by its natural key, or null when none exists — a find
|
||||
/// with no create side-effect. Backs the upload cardinality pre-check, which must read a release's
|
||||
/// medium and live-track count before deciding whether to admit an upload, without creating a
|
||||
/// release for an upload it may reject. The returned DTO carries TrackCount.
|
||||
/// </summary>
|
||||
Task<ResultContainer<ReleaseDto?>> GetReleaseByTitleAndArtist(
|
||||
string title, string artist, CancellationToken cancellationToken = default);
|
||||
|
||||
Task<ResultContainer<TrackDto>> Create(TrackDto newTrack);
|
||||
Task<ResultContainer<TrackDto>> Update(TrackDto track);
|
||||
Task<Result> Delete(long id);
|
||||
|
||||
@@ -201,6 +201,25 @@ public class TrackManager
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<ReleaseDto?>> GetReleaseByTitleAndArtist(
|
||||
string title, string artist, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var existing = await Repository.GetReleaseByTitleAndArtistAsync(title, artist, cancellationToken);
|
||||
if (existing is null)
|
||||
return ResultContainer<ReleaseDto?>.CreatePassResult(null);
|
||||
|
||||
var dto = TrackConverter.Convert(existing);
|
||||
dto.TrackCount = await Repository.CountLiveTracksByReleaseAsync(existing.Id, cancellationToken);
|
||||
return ResultContainer<ReleaseDto?>.CreatePassResult(dto);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return ResultContainer<ReleaseDto?>.CreateFailResult(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<List<GenreSummaryDto>>> GetDistinctGenres(CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user