Merge trackservice-dto: ITrackService/TrackManager flipped to DTO output
This commit is contained in:
@@ -90,7 +90,7 @@
|
||||
@code {
|
||||
[Parameter] public long Id { get; set; }
|
||||
|
||||
private TrackEntity? _track;
|
||||
private TrackDto? _track;
|
||||
private TrackEditForm _form = new();
|
||||
private bool _loading = true;
|
||||
private bool _busy;
|
||||
@@ -199,7 +199,7 @@
|
||||
public string? Genre { get; set; }
|
||||
public DateTime? ReleaseDate { get; set; }
|
||||
|
||||
public static TrackEditForm From(TrackEntity track) => new()
|
||||
public static TrackEditForm From(TrackDto track) => new()
|
||||
{
|
||||
TrackName = track.TrackName,
|
||||
Artist = track.Artist,
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
|
||||
<MudTable T="TrackEntity"
|
||||
<MudTable T="TrackDto"
|
||||
@ref="_table"
|
||||
ServerData="LoadServerData"
|
||||
Hover="true"
|
||||
@@ -37,11 +37,11 @@
|
||||
<MudText Typo="Typo.body1">Loading tracks…</MudText>
|
||||
</LoadingContent>
|
||||
<HeaderContent>
|
||||
<MudTh><MudTableSortLabel SortLabel="TrackName" T="TrackEntity" InitialDirection="SortDirection.Ascending">Track Name</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Artist" T="TrackEntity">Artist</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Album" T="TrackEntity">Album</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Genre" T="TrackEntity">Genre</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="ReleaseDate" T="TrackEntity">Release Date</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="TrackName" T="TrackDto" InitialDirection="SortDirection.Ascending">Track Name</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Artist" T="TrackDto">Artist</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Album" T="TrackDto">Album</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="Genre" T="TrackDto">Genre</MudTableSortLabel></MudTh>
|
||||
<MudTh><MudTableSortLabel SortLabel="ReleaseDate" T="TrackDto">Release Date</MudTableSortLabel></MudTh>
|
||||
<MudTh>Entry Key</MudTh>
|
||||
<MudTh Style="width: 1%; white-space: nowrap;">Actions</MudTh>
|
||||
</HeaderContent>
|
||||
@@ -74,9 +74,9 @@
|
||||
</MudContainer>
|
||||
|
||||
@code {
|
||||
private MudTable<TrackEntity>? _table;
|
||||
private MudTable<TrackDto>? _table;
|
||||
|
||||
private async Task<TableData<TrackEntity>> LoadServerData(TableState state, CancellationToken cancellationToken)
|
||||
private async Task<TableData<TrackDto>> LoadServerData(TableState state, CancellationToken cancellationToken)
|
||||
{
|
||||
var pageNumber = state.Page + 1; // MudTable is 0-based, service is 1-based.
|
||||
var sortColumn = string.IsNullOrEmpty(state.SortLabel) ? "TrackName" : state.SortLabel;
|
||||
@@ -88,18 +88,18 @@
|
||||
{
|
||||
var errorText = result.Messages.FirstOrDefault()?.Message ?? "Unknown error";
|
||||
Snackbar.Add($"Failed to load tracks: {errorText}", Severity.Error);
|
||||
return new TableData<TrackEntity> { Items = Array.Empty<TrackEntity>(), TotalItems = 0 };
|
||||
return new TableData<TrackDto> { Items = Array.Empty<TrackDto>(), TotalItems = 0 };
|
||||
}
|
||||
|
||||
var page = result.Value;
|
||||
return new TableData<TrackEntity>
|
||||
return new TableData<TrackDto>
|
||||
{
|
||||
Items = page.Items,
|
||||
TotalItems = page.TotalCount
|
||||
};
|
||||
}
|
||||
|
||||
private async Task ConfirmAndDelete(TrackEntity track)
|
||||
private async Task ConfirmAndDelete(TrackDto track)
|
||||
{
|
||||
var confirmed = await DialogService.ShowMessageBox(
|
||||
title: "Delete track",
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
@using AuthBlocksWeb.Components
|
||||
@using DeepDrftManager
|
||||
@using DeepDrftManager.Components
|
||||
@using DeepDrftModels.Entities
|
||||
@using DeepDrftModels.DTOs
|
||||
@using Models.Common
|
||||
@using AuthBlocksModels.SystemDefinitions
|
||||
@using AuthBlocksWeb.HierarchicalAuthorize
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
using DeepDrftModels.Entities;
|
||||
using DeepDrftModels.DTOs;
|
||||
using Models.Common;
|
||||
using NetBlocks.Models;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class CmsTrackService : ICmsTrackService
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<TrackEntity>> UploadTrackAsync(
|
||||
public async Task<ResultContainer<TrackDto>> UploadTrackAsync(
|
||||
Stream wavStream,
|
||||
string fileName,
|
||||
string contentType,
|
||||
@@ -67,7 +67,7 @@ public class CmsTrackService : ICmsTrackService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Content API call failed for upload of {TrackName}", trackName);
|
||||
return ResultContainer<TrackEntity>.CreateFailResult("Content API is unreachable.");
|
||||
return ResultContainer<TrackDto>.CreateFailResult("Content API is unreachable.");
|
||||
}
|
||||
|
||||
using (response)
|
||||
@@ -79,35 +79,35 @@ public class CmsTrackService : ICmsTrackService
|
||||
if (statusCode >= 500)
|
||||
{
|
||||
_logger.LogError("Content API returned {Status} for upload of {TrackName}: {Body}", statusCode, trackName, body);
|
||||
return ResultContainer<TrackEntity>.CreateFailResult("Upload failed on the content server. Please try again.");
|
||||
return ResultContainer<TrackDto>.CreateFailResult("Upload failed on the content server. Please try again.");
|
||||
}
|
||||
|
||||
// 4xx: body is user-friendly validation text from DeepDrftAPI — relay as-is.
|
||||
_logger.LogWarning("Content API rejected upload: {Status} {Body}", statusCode, body);
|
||||
return ResultContainer<TrackEntity>.CreateFailResult(
|
||||
return ResultContainer<TrackDto>.CreateFailResult(
|
||||
string.IsNullOrWhiteSpace(body) ? $"Upload rejected ({statusCode})." : body);
|
||||
}
|
||||
|
||||
// The Content API now owns the dual-database write, so the response is the persisted
|
||||
// entity (Id > 0) — no SQL roundtrip here.
|
||||
TrackEntity? persisted;
|
||||
// track DTO (Id > 0) — no SQL roundtrip here.
|
||||
TrackDto? persisted;
|
||||
try
|
||||
{
|
||||
persisted = await response.Content.ReadFromJsonAsync<TrackEntity>(ct);
|
||||
persisted = await response.Content.ReadFromJsonAsync<TrackDto>(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to deserialize TrackEntity from Content API response");
|
||||
return ResultContainer<TrackEntity>.CreateFailResult("Content API returned an unexpected response.");
|
||||
_logger.LogError(ex, "Failed to deserialize TrackDto from Content API response");
|
||||
return ResultContainer<TrackDto>.CreateFailResult("Content API returned an unexpected response.");
|
||||
}
|
||||
|
||||
if (persisted is null)
|
||||
{
|
||||
_logger.LogError("Content API returned a null TrackEntity");
|
||||
return ResultContainer<TrackEntity>.CreateFailResult("Content API returned an empty response.");
|
||||
_logger.LogError("Content API returned a null TrackDto");
|
||||
return ResultContainer<TrackDto>.CreateFailResult("Content API returned an empty response.");
|
||||
}
|
||||
|
||||
return ResultContainer<TrackEntity>.CreatePassResult(persisted);
|
||||
return ResultContainer<TrackDto>.CreatePassResult(persisted);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class CmsTrackService : ICmsTrackService
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<PagedResult<TrackEntity>>> GetPagedAsync(
|
||||
public async Task<ResultContainer<PagedResult<TrackDto>>> GetPagedAsync(
|
||||
int page, int pageSize, string? sortColumn, bool sortDescending,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
@@ -163,7 +163,7 @@ public class CmsTrackService : ICmsTrackService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Content API call failed for track page");
|
||||
return ResultContainer<PagedResult<TrackEntity>>.CreateFailResult("Content API is unreachable.");
|
||||
return ResultContainer<PagedResult<TrackDto>>.CreateFailResult("Content API is unreachable.");
|
||||
}
|
||||
|
||||
using (response)
|
||||
@@ -171,31 +171,31 @@ public class CmsTrackService : ICmsTrackService
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogError("Content API track page failed: {Status}", (int)response.StatusCode);
|
||||
return ResultContainer<PagedResult<TrackEntity>>.CreateFailResult("Failed to load tracks.");
|
||||
return ResultContainer<PagedResult<TrackDto>>.CreateFailResult("Failed to load tracks.");
|
||||
}
|
||||
|
||||
PagedResult<TrackEntity>? paged;
|
||||
PagedResult<TrackDto>? paged;
|
||||
try
|
||||
{
|
||||
paged = await response.Content.ReadFromJsonAsync<PagedResult<TrackEntity>>(ct);
|
||||
paged = await response.Content.ReadFromJsonAsync<PagedResult<TrackDto>>(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to deserialize PagedResult from Content API response");
|
||||
return ResultContainer<PagedResult<TrackEntity>>.CreateFailResult("Content API returned an unexpected response.");
|
||||
return ResultContainer<PagedResult<TrackDto>>.CreateFailResult("Content API returned an unexpected response.");
|
||||
}
|
||||
|
||||
if (paged is null)
|
||||
{
|
||||
_logger.LogError("Content API returned a null PagedResult");
|
||||
return ResultContainer<PagedResult<TrackEntity>>.CreateFailResult("Content API returned an empty response.");
|
||||
return ResultContainer<PagedResult<TrackDto>>.CreateFailResult("Content API returned an empty response.");
|
||||
}
|
||||
|
||||
return ResultContainer<PagedResult<TrackEntity>>.CreatePassResult(paged);
|
||||
return ResultContainer<PagedResult<TrackDto>>.CreatePassResult(paged);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ResultContainer<TrackEntity?>> GetByIdAsync(long id, CancellationToken ct = default)
|
||||
public async Task<ResultContainer<TrackDto?>> GetByIdAsync(long id, CancellationToken ct = default)
|
||||
{
|
||||
var client = _httpClientFactory.CreateClient(ContentCmsClientName);
|
||||
|
||||
@@ -207,34 +207,34 @@ public class CmsTrackService : ICmsTrackService
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Content API call failed for track {TrackId}", id);
|
||||
return ResultContainer<TrackEntity?>.CreateFailResult("Content API is unreachable.");
|
||||
return ResultContainer<TrackDto?>.CreateFailResult("Content API is unreachable.");
|
||||
}
|
||||
|
||||
using (response)
|
||||
{
|
||||
if (response.StatusCode == HttpStatusCode.NotFound)
|
||||
{
|
||||
return ResultContainer<TrackEntity?>.CreatePassResult(null);
|
||||
return ResultContainer<TrackDto?>.CreatePassResult(null);
|
||||
}
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
_logger.LogError("Content API track lookup failed for {TrackId}: {Status}", id, (int)response.StatusCode);
|
||||
return ResultContainer<TrackEntity?>.CreateFailResult("Failed to load track.");
|
||||
return ResultContainer<TrackDto?>.CreateFailResult("Failed to load track.");
|
||||
}
|
||||
|
||||
TrackEntity? track;
|
||||
TrackDto? track;
|
||||
try
|
||||
{
|
||||
track = await response.Content.ReadFromJsonAsync<TrackEntity>(ct);
|
||||
track = await response.Content.ReadFromJsonAsync<TrackDto>(ct);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Failed to deserialize TrackEntity from Content API response");
|
||||
return ResultContainer<TrackEntity?>.CreateFailResult("Content API returned an unexpected response.");
|
||||
_logger.LogError(ex, "Failed to deserialize TrackDto from Content API response");
|
||||
return ResultContainer<TrackDto?>.CreateFailResult("Content API returned an unexpected response.");
|
||||
}
|
||||
|
||||
return ResultContainer<TrackEntity?>.CreatePassResult(track);
|
||||
return ResultContainer<TrackDto?>.CreatePassResult(track);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using DeepDrftModels.Entities;
|
||||
using DeepDrftModels.DTOs;
|
||||
using Models.Common;
|
||||
using NetBlocks.Models;
|
||||
|
||||
@@ -13,10 +13,10 @@ public interface ICmsTrackService
|
||||
{
|
||||
/// <summary>
|
||||
/// Proxy a WAV upload to DeepDrftAPI. The Content API owns the dual-database write and
|
||||
/// returns the persisted entity carrying the SQL-assigned <c>Id</c>. A vault-without-SQL
|
||||
/// returns the persisted track carrying the SQL-assigned <c>Id</c>. A vault-without-SQL
|
||||
/// orphan is handled and logged server-side; here it surfaces as a failed result.
|
||||
/// </summary>
|
||||
Task<ResultContainer<TrackEntity>> UploadTrackAsync(
|
||||
Task<ResultContainer<TrackDto>> UploadTrackAsync(
|
||||
Stream wavStream,
|
||||
string fileName,
|
||||
string contentType,
|
||||
@@ -37,7 +37,7 @@ public interface ICmsTrackService
|
||||
/// <summary>
|
||||
/// Fetch a page of track metadata from the Content API's <c>GET api/track/page</c>.
|
||||
/// </summary>
|
||||
Task<ResultContainer<PagedResult<TrackEntity>>> GetPagedAsync(
|
||||
Task<ResultContainer<PagedResult<TrackDto>>> GetPagedAsync(
|
||||
int page, int pageSize, string? sortColumn, bool sortDescending,
|
||||
CancellationToken ct = default);
|
||||
|
||||
@@ -45,7 +45,7 @@ public interface ICmsTrackService
|
||||
/// Fetch a single track's metadata from <c>GET api/track/meta/{id}</c>. A 404 returns a
|
||||
/// passing result with a null value.
|
||||
/// </summary>
|
||||
Task<ResultContainer<TrackEntity?>> GetByIdAsync(long id, CancellationToken ct = default);
|
||||
Task<ResultContainer<TrackDto?>> GetByIdAsync(long id, CancellationToken ct = default);
|
||||
|
||||
/// <summary>
|
||||
/// Update a track's metadata via <c>PUT api/track/meta/{id}</c>. EntryKey is immutable and
|
||||
|
||||
Reference in New Issue
Block a user