From e3348860224bb76360af0720d3aeaa1ad1714944 Mon Sep 17 00:00:00 2001 From: Daniel Harvey Date: Mon, 25 May 2026 12:55:30 -0400 Subject: [PATCH] Eliminate DeepDrftPublic internal track API --- DeepDrftAPI/Controllers/TrackController.cs | 3 +- DeepDrftPublic.Client/Clients/TrackClient.cs | 27 ++++++---- DeepDrftPublic.Client/Program.cs | 3 +- DeepDrftPublic.Client/Startup.cs | 5 +- .../wwwroot/appsettings.json | 3 +- DeepDrftPublic/Controllers/TrackController.cs | 33 ------------ DeepDrftPublic/DeepDrftPublic.csproj | 1 - DeepDrftPublic/Program.cs | 16 +----- .../Services/TrackDirectDataService.cs | 33 ------------ DeepDrftPublic/Startup.cs | 50 ------------------- DeepDrftPublic/appsettings.json | 3 +- 11 files changed, 27 insertions(+), 150 deletions(-) delete mode 100644 DeepDrftPublic/Controllers/TrackController.cs delete mode 100644 DeepDrftPublic/Services/TrackDirectDataService.cs diff --git a/DeepDrftAPI/Controllers/TrackController.cs b/DeepDrftAPI/Controllers/TrackController.cs index 6d7ed4e..b9414c3 100644 --- a/DeepDrftAPI/Controllers/TrackController.cs +++ b/DeepDrftAPI/Controllers/TrackController.cs @@ -47,8 +47,7 @@ public class TrackController : ControllerBase // resolution never treats "page", "upload", or "meta" as a trackId. // GET api/track/page?page=1&pageSize=20&sortColumn=TrackName&sortDescending=false - // CMS metadata listing — paged read straight from SQL. - [ApiKeyAuthorize] + // Public track listing — paged read straight from SQL. Unauthenticated, like GET api/track/{id}. [HttpGet("page")] public async Task GetPage( [FromQuery] int page = 1, diff --git a/DeepDrftPublic.Client/Clients/TrackClient.cs b/DeepDrftPublic.Client/Clients/TrackClient.cs index 3a75d69..f4681e4 100644 --- a/DeepDrftPublic.Client/Clients/TrackClient.cs +++ b/DeepDrftPublic.Client/Clients/TrackClient.cs @@ -17,32 +17,37 @@ public class TrackClient } public async Task>> GetPage( - int pageNumber, - int pageSize, - string? sortColumn = null, + int pageNumber, + int pageSize, + string? sortColumn = null, bool sortDescending = false) { var queryArgs = new Dictionary(){ - ["pageNumber"] = pageNumber.ToString(), + ["page"] = pageNumber.ToString(), ["pageSize"] = pageSize.ToString() }; - + if (!string.IsNullOrEmpty(sortColumn)) queryArgs["sortColumn"] = sortColumn; - + if (sortDescending) queryArgs["sortDescending"] = "true"; string query = QueryString.Create(queryArgs).ToString(); - + var response = await _http.GetAsync($"api/track/page{query}"); + + if (!response.IsSuccessStatusCode) + return ApiResult>.CreateFailResult($"HTTP {(int)response.StatusCode}"); + var json = await response.Content.ReadAsStringAsync(); - - var dto = JsonSerializer.Deserialize>>(json, new JsonSerializerOptions + var paged = JsonSerializer.Deserialize>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); - - return dto?.From() ?? ApiResult>.CreateFailResult("Failed to deserialize response"); + + return paged is not null + ? ApiResult>.CreatePassResult(paged) + : ApiResult>.CreateFailResult("Failed to deserialize response"); } } \ No newline at end of file diff --git a/DeepDrftPublic.Client/Program.cs b/DeepDrftPublic.Client/Program.cs index 147012e..300c3bc 100644 --- a/DeepDrftPublic.Client/Program.cs +++ b/DeepDrftPublic.Client/Program.cs @@ -7,10 +7,11 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args); Console.WriteLine(builder.HostEnvironment.BaseAddress); var contentApiUrl = builder.Configuration["ApiUrls:ContentApi"] ?? "https://localhost:7001"; +var sqlApiUrl = builder.Configuration["ApiUrls:SqlApi"] ?? "https://localhost:5002"; builder.Services.AddMudServices(); -Startup.ConfigureApiHttpClient(builder.Services, builder.HostEnvironment.BaseAddress); +Startup.ConfigureApiHttpClient(builder.Services, sqlApiUrl); Startup.ConfigureContentServices(builder.Services, contentApiUrl); Startup.ConfigureDomainServices(builder.Services); diff --git a/DeepDrftPublic.Client/Startup.cs b/DeepDrftPublic.Client/Startup.cs index 0858ad7..fa8ed89 100644 --- a/DeepDrftPublic.Client/Startup.cs +++ b/DeepDrftPublic.Client/Startup.cs @@ -14,9 +14,8 @@ public static class Startup services.AddScoped(); services.AddScoped(); - // Track Client. The HTTP-backed ITrackDataService registration here is the WASM - // default; the server host overrides it with an in-process implementation after - // this method runs, so SSR prerender skips the loopback hop. + // Track Client. The HTTP-backed ITrackDataService is used by both WASM and SSR + // prerender — both call DeepDrftAPI over the "DeepDrft.API" client. services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/DeepDrftPublic.Client/wwwroot/appsettings.json b/DeepDrftPublic.Client/wwwroot/appsettings.json index e6588d2..0ef5f55 100644 --- a/DeepDrftPublic.Client/wwwroot/appsettings.json +++ b/DeepDrftPublic.Client/wwwroot/appsettings.json @@ -6,6 +6,7 @@ } }, "ApiUrls": { - "ContentApi": "https://media.deepdrft.com/" + "ContentApi": "https://media.deepdrft.com/", + "SqlApi": "https://api.deepdrft.com/" } } diff --git a/DeepDrftPublic/Controllers/TrackController.cs b/DeepDrftPublic/Controllers/TrackController.cs deleted file mode 100644 index f4d1164..0000000 --- a/DeepDrftPublic/Controllers/TrackController.cs +++ /dev/null @@ -1,33 +0,0 @@ -using DeepDrftData; -using DeepDrftModels.DTOs; -using Microsoft.AspNetCore.Mvc; -using Models.Common; -using NetBlocks.Models; - -namespace DeepDrftPublic.Controllers; - -[ApiController] -[Route("api/[controller]")] -public class TrackController : ControllerBase -{ - private readonly ITrackService _trackService; - - public TrackController(ITrackService trackService) - { - _trackService = trackService; - } - - [HttpGet("page")] - public async Task>>> GetPage( - [FromQuery] int pageNumber, - [FromQuery] int pageSize, - [FromQuery] string? sortColumn = null, - [FromQuery] bool sortDescending = false) - { - var result = await _trackService.GetPaged(pageNumber, pageSize, sortColumn, sortDescending); - var apiResult = ApiResult>.From(result); - var dto = new ApiResultDto>(apiResult); - - return result.Success ? Ok(dto) : StatusCode(500, dto); - } -} \ No newline at end of file diff --git a/DeepDrftPublic/DeepDrftPublic.csproj b/DeepDrftPublic/DeepDrftPublic.csproj index db3433f..ce498ee 100644 --- a/DeepDrftPublic/DeepDrftPublic.csproj +++ b/DeepDrftPublic/DeepDrftPublic.csproj @@ -22,7 +22,6 @@ - diff --git a/DeepDrftPublic/Program.cs b/DeepDrftPublic/Program.cs index c5294c9..c5d0a88 100644 --- a/DeepDrftPublic/Program.cs +++ b/DeepDrftPublic/Program.cs @@ -2,32 +2,21 @@ using DeepDrftPublic; using MudBlazor.Services; using DeepDrftPublic.Components; using Microsoft.AspNetCore.HttpOverrides; -using NetBlocks.Utilities.Environment; var builder = WebApplication.CreateBuilder(args); // Add MudBlazor services builder.Services.AddMudServices(); -// Required credential files — must exist before the app will start. -// In dev: create the files under DeepDrftPublic/environment/ (gitignored). -// In prod: systemd CREDENTIALS_DIRECTORY points to encrypted credential blobs. -// - environment/connections.json: { "ConnectionStrings": { "DefaultConnection": "..." } } -// AuthBlocks and the DeepDrftAPI API key now live on DeepDrftManager; -// the public host has no auth surface and no CMS upload proxy. -var connectionsPath = CredentialTools.ResolvePathOrThrow("connections", "environment/connections.json"); -builder.Configuration.AddJsonFile(connectionsPath, optional: false, reloadOnChange: false); - var contentApiUrl = builder.Configuration["ApiUrls:ContentApi"] ?? throw new Exception("Content API URL is not configured"); +var sqlApiUrl = builder.Configuration["ApiUrls:SqlApi"] ?? throw new Exception("ApiUrls:SqlApi is not configured"); -DeepDrftPublic.Client.Startup.ConfigureApiHttpClient(builder.Services, builder.GetKestrelUrl()); +DeepDrftPublic.Client.Startup.ConfigureApiHttpClient(builder.Services, sqlApiUrl); DeepDrftPublic.Client.Startup.ConfigureDomainServices(builder.Services); DeepDrftPublic.Client.Startup.ConfigureContentServices(builder.Services, contentApiUrl); Startup.ConfigureDomainServices(builder); -builder.Services.AddControllers(); - // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents() @@ -110,7 +99,6 @@ if (app.Environment.IsDevelopment()) }); } -app.MapControllers(); app.MapRazorComponents() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode() diff --git a/DeepDrftPublic/Services/TrackDirectDataService.cs b/DeepDrftPublic/Services/TrackDirectDataService.cs deleted file mode 100644 index 31676b1..0000000 --- a/DeepDrftPublic/Services/TrackDirectDataService.cs +++ /dev/null @@ -1,33 +0,0 @@ -using DeepDrftData; -using DeepDrftModels.DTOs; -using DeepDrftPublic.Client.Services; -using Models.Common; -using NetBlocks.Models; - -namespace DeepDrftPublic.Services; - -/// -/// Server-side that calls -/// in-process (EF Core / SQL). Replaces the loopback HTTP hop during SSR prerender: -/// the WASM interactive pass still uses -/// over HTTP, but on the server we already have the domain service in DI. -/// -public class TrackDirectDataService : ITrackDataService -{ - private readonly ITrackService _trackService; - - public TrackDirectDataService(ITrackService trackService) - { - _trackService = trackService; - } - - public async Task>> GetPage( - int pageNumber, - int pageSize, - string? sortColumn = null, - bool sortDescending = false) - { - var result = await _trackService.GetPaged(pageNumber, pageSize, sortColumn, sortDescending); - return ApiResult>.From(result); - } -} diff --git a/DeepDrftPublic/Startup.cs b/DeepDrftPublic/Startup.cs index 61ca8cf..4ab30e1 100644 --- a/DeepDrftPublic/Startup.cs +++ b/DeepDrftPublic/Startup.cs @@ -1,9 +1,4 @@ -using DeepDrftData; -using DeepDrftData.Data; -using DeepDrftData.Repositories; -using DeepDrftPublic.Client.Services; using DeepDrftPublic.Services; // DarkModeService namespace (within this host project) -using Microsoft.EntityFrameworkCore; namespace DeepDrftPublic; @@ -11,55 +6,10 @@ public static class Startup { public static void ConfigureDomainServices(WebApplicationBuilder builder) { - // Add Entity Framework services - builder.Services.AddDbContext(options => - options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection"))); - // Add Server Prerendering Theming Support // DarkModeSettings is registered in DeepDrftPublic.Client.Startup.ConfigureDomainServices builder.Services .AddHttpContextAccessor() .AddScoped(); - - // Add Track services. TrackManager implements ITrackService for backward compatibility - // with pages that inject the interface; resolving ITrackService returns the same scoped - // TrackManager instance so the manager surface (DTO-space) and the service surface - // (entity-space) share state. - builder.Services - .AddScoped() - .AddScoped() - .AddScoped(sp => sp.GetRequiredService()); - - // Override the WASM HTTP-backed ITrackDataService (registered earlier by - // DeepDrftPublic.Client.Startup.ConfigureDomainServices) with an in-process - // adapter for SSR prerender. Last registration wins for single-resolution. - builder.Services.AddScoped(); - } - - public static string GetKestrelUrl(this WebApplicationBuilder builder) - { - // Check all the places Kestrel URL can be configured - var urls = builder.Configuration["ASPNETCORE_URLS"] - ?? builder.Configuration["urls"]; - - if (!string.IsNullOrEmpty(urls)) - { - return urls.Split(';')[0].Trim(); - } - - // Check Kestrel endpoints configuration - var kestrelSection = builder.Configuration.GetSection("Kestrel:Endpoints"); - var firstEndpoint = kestrelSection.GetChildren().FirstOrDefault(); - var endpointUrl = firstEndpoint?["Url"]; - - if (!string.IsNullOrEmpty(endpointUrl)) - { - return endpointUrl; - } - - // ASP.NET Core defaults - return builder.Environment.IsDevelopment() - ? "https://localhost:5001" - : "http://localhost:5000"; } } diff --git a/DeepDrftPublic/appsettings.json b/DeepDrftPublic/appsettings.json index 6f4ca4f..aba08d6 100644 --- a/DeepDrftPublic/appsettings.json +++ b/DeepDrftPublic/appsettings.json @@ -7,7 +7,8 @@ }, "AllowedHosts": "*", "ApiUrls": { - "ContentApi": "http://localhost:12777/" + "ContentApi": "http://localhost:12777/", + "SqlApi": "https://localhost:5002" }, "ForwardedHeaders": { "DisableHttpsRedirection": "true"