From bcdff4b3950b61a3195ff05501b1a81787e72f0f Mon Sep 17 00:00:00 2001 From: Phil-NHS Date: Fri, 1 Aug 2025 09:59:17 +0100 Subject: [PATCH 1/8] TD-5888 adding blazor serverside and TELBlazor package ref --- .gitignore | 1 + .../BlazorPageHosting/App.razor | 1 + .../LearningHub.Nhs.WebUI.csproj | 10 +++++++ LearningHub.Nhs.WebUI/Program.cs | 13 ++++++++- LearningHub.Nhs.WebUI/nuget.config.template | 28 +++++++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 LearningHub.Nhs.WebUI/BlazorPageHosting/App.razor create mode 100644 LearningHub.Nhs.WebUI/nuget.config.template diff --git a/.gitignore b/.gitignore index 8cc7d8bbe..f4ca20bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,4 @@ obj /AdminUI/LearningHub.Nhs.AdminUI/web.config /LearningHub.Nhs.WebUI/web.config /WebAPI/LearningHub.Nhs.API/web.config +/LearningHub.Nhs.WebUI/nuget.config diff --git a/LearningHub.Nhs.WebUI/BlazorPageHosting/App.razor b/LearningHub.Nhs.WebUI/BlazorPageHosting/App.razor new file mode 100644 index 000000000..884020c95 --- /dev/null +++ b/LearningHub.Nhs.WebUI/BlazorPageHosting/App.razor @@ -0,0 +1 @@ +@* No-op App component *@ diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj index caaf79c03..345fff7db 100644 --- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj +++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj @@ -97,6 +97,9 @@ + + + @@ -104,6 +107,13 @@ + + + + + + + diff --git a/LearningHub.Nhs.WebUI/Program.cs b/LearningHub.Nhs.WebUI/Program.cs index c24d9057c..e6540a821 100644 --- a/LearningHub.Nhs.WebUI/Program.cs +++ b/LearningHub.Nhs.WebUI/Program.cs @@ -2,6 +2,7 @@ using System; using System.Diagnostics; using LearningHub.Nhs.WebUI; +using LearningHub.Nhs.WebUI.BlazorPageHosting; using LearningHub.Nhs.WebUI.Interfaces; using LearningHub.Nhs.WebUI.JsDetection; using LearningHub.Nhs.WebUI.Middleware; @@ -18,7 +19,6 @@ using tusdotnet; using tusdotnet.Models; using tusdotnet.Models.Configuration; - #pragma warning restore SA1200 // Using directives should be placed correctly var logger = NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger(); @@ -43,10 +43,13 @@ var appLifetime = app.Services.GetRequiredService(); var jsDetectionLogger = app.Services.GetRequiredService(); appLifetime.ApplicationStopping.Register(async () => await jsDetectionLogger.FlushCounters()); + app.UseBlazorFrameworkFiles(); + app.UseStaticFiles(); if (app.Environment.IsDevelopment()) { app.UseDeveloperExceptionPage(); + app.UseWebAssemblyDebugging(); } else { @@ -108,6 +111,14 @@ }; }); + app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + + // .AddAdditionalAssemblies(typeof(LearningHub.Nhs.WebUI.BlazorComponents._Imports).Assembly) // qqqq later + // .AddAdditionalAssemblies(typeof(LearningHub.Nhs.WebUI.BlazorClient._Imports).Assembly); qqqq later + .AddAdditionalAssemblies(typeof(TELBlazor.Components._Imports).Assembly); + app.Run(); } catch (Exception ex) diff --git a/LearningHub.Nhs.WebUI/nuget.config.template b/LearningHub.Nhs.WebUI/nuget.config.template new file mode 100644 index 000000000..dac496006 --- /dev/null +++ b/LearningHub.Nhs.WebUI/nuget.config.template @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From ce07ada1eb863d1b611f9c386624d17be570cb83 Mon Sep 17 00:00:00 2001 From: Phil-NHS Date: Fri, 1 Aug 2025 12:33:04 +0100 Subject: [PATCH 2/8] TD-5888 Builds, requires httpclient and comments tidying --- .gitignore | 4 + .../LearningHub.Nhs.WebUI.BlazorClient.csproj | 53 ++++++ ...ningHub.Nhs.WebUI.BlazorClient.csproj.user | 6 + LearningHub.Nhs.WebUI.BlazorClient/Program.cs | 159 ++++++++++++++++++ .../Services/GenericAPIHttpClient.cs | 30 ++++ .../Services/WasmCacheServiceStub.cs | 61 +++++++ .../_Imports.razor | 1 + .../nuget.config.template | 28 +++ LearningHub.Nhs.WebUI.sln | 10 ++ .../LearningHub.Nhs.WebUI.csproj | 3 +- 10 files changed, 354 insertions(+), 1 deletion(-) create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/Program.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/nuget.config.template diff --git a/.gitignore b/.gitignore index f4ca20bfa..3b61a883d 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,7 @@ obj /LearningHub.Nhs.WebUI/web.config /WebAPI/LearningHub.Nhs.API/web.config /LearningHub.Nhs.WebUI/nuget.config +/LearningHub.Nhs.WebUI.BlazorClient/Properties/launchSettings.json +/LearningHub.Nhs.WebUI.BlazorClient/wwwroot/appsettings.json +/LearningHub.Nhs.WebUI.BlazorClient/wwwroot/appsettings.Development.json +/LearningHub.Nhs.WebUI.BlazorClient/nuget.config diff --git a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj new file mode 100644 index 000000000..ce506bf11 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj @@ -0,0 +1,53 @@ + + + + net8.0 + enable + enable + true + full + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user new file mode 100644 index 000000000..9ff5820a2 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user @@ -0,0 +1,6 @@ + + + + https + + \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs new file mode 100644 index 000000000..3aea91207 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs @@ -0,0 +1,159 @@ +// Microsoft namespaces + +//using LearningHub.Nhs.Models.Entities; +// Still required server side even if not used so components dont fail +using Blazored.LocalStorage; +using LearningHub.Nhs.Caching; +using LearningHub.Nhs.WebUI.BlazorClient.Services; +using LearningHub.Nhs.Shared.Configuration; +using LearningHub.Nhs.Shared.Interfaces; +using LearningHub.Nhs.Shared.Services; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +// Serilog core (used via appsettings, do not delete even if vs marks not in use) +using Serilog; +using Serilog.Configuration; +using Serilog.Core; +using Serilog.Events; +// Serilog extensions and sinks (used via appsettings, do not delete even if vs marks not in use) +using Serilog.Extensions.Logging; +using Serilog.Formatting.Compact; +using Serilog.Settings.Configuration; +using Serilog.Sinks.BrowserConsole; +using TELBlazor.Components.Core.Configuration; +using TELBlazor.Components.Core.Services.HelperServices; +using TELBlazor.Components.OptionalImplementations.Core.Services.HelperServices; +using TELBlazor.Components.OptionalImplementations.Test.TestComponents.SearchExperiment; +using LearningHub.Nhs.Shared.Interfaces.Services; + + + + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; + +builder.Configuration.AddJsonFile($"appsettings.{environment}.json", optional: false, reloadOnChange: true); + +builder.Logging.ClearProviders(); + + +// Read default logging level from configuration +var logLevelString = builder.Configuration["Serilog:MinimumLevel:Default"]; +// Convert string to LogEventLevel (with fallback) +if (!Enum.TryParse(logLevelString, true, out LogEventLevel defaultLogLevel)) +{ + defaultLogLevel = LogEventLevel.Information; // Default if parsing fails +} + +// Create a LoggingLevelSwitch that can be updated dynamically +LoggingLevelSwitch levelSwitch = new LoggingLevelSwitch(defaultLogLevel); // Default: Information added this so in production can change the logging +Log.Logger = new LoggerConfiguration() + .ReadFrom.Configuration(builder.Configuration) + .MinimumLevel.ControlledBy(levelSwitch) + .CreateLogger(); + +// Add Serilog to logging providers +builder.Logging.AddSerilog(Log.Logger, dispose: true);//qqqq may not need dispose for client + + + + + +//for really bad fails +try +{ + // Candidates for DI collection + builder.Services.AddSingleton(sp => + { + return new TELBlazorBaseComponentConfiguration + { + JSEnabled = true, //if we are inject the client then it is true + HostType = $"{builder.Configuration["Properties:Environment"]} {builder.Configuration["Properties:Application"]}" + }; + }); + + + builder.Services.AddBlazoredLocalStorage(); //could make our own caching with this client side ... but needs careful consideration of managing two sets of cache for pages of mixed mvc and blazor components + + + //this.findwiseSettings = findwiseSettings.Value; + //this.publicSettings = publicSettings.Value; + builder.Configuration.AddJsonFile($"appsettings.{environment}.json", optional: true); + builder.Services.Configure(builder.Configuration.GetSection("Settings")); + + //!!!!! builder.Services.Configure(builder.Configuration.GetSection("Settings"));//qqqq we cannot do this in actuality there are security things inthsi + //Scoped because being consumed with storage where singleton doesnt survive mvc page teardown + //qqqq do we need it + //builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + + // Register your BFF-pointing clients + + //builder.Services.AddHttpClient(client => { + // client.BaseAddress = new Uri("https://localhost:5001/bff/lh-web/"); // or whatever your BFF port is + //}); + + + //we want to do this - oh but it wont be in domain! + // it will be https://lh-web.dev.local/bff/ the api name so we need to set the name the same ... it doesnt need to be the same but may aswell + // the other local ones are https://lh-web.dev.local/api/ + + //"LearningHubUrl": "https://bff/lh-web.dev.local/", + //"ELfhHubUrl": "https://bff/test-portal.e-lfhtech.org.uk ", + //"LearningHubApiUrl": "https://bff/lh-api.dev.local/api/", + //"UserApiUrl": "https://bff/lh-userapi.dev.local/api/", + //"LearningHubAdminUrl": "https://bff/lh-admin.dev.local/", + + + //"LearningHubUrl": "https://lh-web.dev.local/", + //"ELfhHubUrl": "https://test-portal.e-lfhtech.org.uk ", + //"LearningHubApiUrl": "https://lh-api.dev.local/api/", + //"UserApiUrl": "https://lh-userapi.dev.local/api/", + //"LearningHubAdminUrl": "https://lh-admin.dev.local/", + + + + //builder.Services.AddHttpClient(client => { + // client.BaseAddress = new Uri("https://localhost:5001/bff/lh-userapi/"); + //}); + // LearningHubApiUrl -> //"LearningHubApiUrl": "https://lh-web.dev.local/bff/Catalogue/GetLatestCatalogueAccessRequest/500/lh-api.dev.local/api/", --> //"LearningHubApiUrl": "https://lh-api.dev.local/api/", + + // qqqq put back in + //builder.Services.AddHttpClient(client => { + // client.BaseAddress = new Uri("https://lh-web.dev.local/bff/lh-api.dev.local/"); // or whatever your BFF port is + //}); + + //// //"UserApiUrl": "https://bff/lh-userapi.dev.local/api/", --> //"UserApiUrl": "https://lh-userapi.dev.local/api/", + //builder.Services.AddHttpClient(client => { + // client.BaseAddress = new Uri("https://lh-web.dev.local/bff/lh-userapi.dev.local/"); + //}); + + builder.Services.AddScoped(sp => levelSwitch); + builder.Services.AddScoped(); + + builder.Services.AddScoped(); // had to change provider not to use it previously trying again + builder.Services.AddScoped(); + + + + //qqqq Register IOptions - requires manual binding in WASM + // --> qqqq MONDAY Important: In Blazor WASM, IOptions works only if the configuration is available at runtime.That means you must ensure that your appsettings.json or other configuration is correctly loaded into builder.Configuration. + + + + await builder.Build().RunAsync(); +} +catch (Exception ex) +{ + //If in production as requires sending to api we may never receive it + Log.Fatal(ex, "Application terminated unexpectedly"); +} +finally +{ + Log.CloseAndFlush(); // Ensure logs are flushed before exit +} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs new file mode 100644 index 000000000..d200b2288 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs @@ -0,0 +1,30 @@ +using LearningHub.Nhs.Shared.Interfaces.Http; + +namespace LearningHub.Nhs.WebUI.BlazorClient.Services +{ + public class GenericAPIHttpClient : IAPIHttpClient, ILearningHubHttpClient, IUserApiHttpClient // Implementing multiple interfaces + { + private readonly HttpClient _httpClient; // Private field to hold the injected HttpClient + + /// + /// Initializes a new instance of the class. + /// + /// The HttpClient instance provided by dependency injection. + public GenericAPIHttpClient(HttpClient httpClient) // Inject HttpClient + { + _httpClient = httpClient; + } + + public string ApiUrl => _httpClient.BaseAddress.AbsoluteUri; + + /// + /// Retrieves the configured HttpClient instance. + /// + /// A Task that resolves to the HttpClient instance. + public Task GetClientAsync() + { + // Return the injected HttpClient instance wrapped in a completed Task + return Task.FromResult(_httpClient); + } + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs new file mode 100644 index 000000000..67836f39f --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs @@ -0,0 +1,61 @@ +using LearningHub.Nhs.Caching; + +namespace LearningHub.Nhs.WebUI.BlazorClient.Services +{ + /// + /// We may use storage, we may just stub it and throw an error, we cant directly use redis we may access it via an api + /// + public class WasmCacheServiceStub : ICacheService + { + public Task GetAsync(string key) + { + return Task.FromResult(default(T)); + } + + public Task<(bool Success, T Value)> TryGetAsync(string key) + { + return Task.FromResult((false, default(T))); + } + + public Task SetAsync(string key, T value) + { + return Task.FromResult(value); + } + + public Task RemoveAsync(string key) + { + return Task.CompletedTask; + } + + public Task SetAsync(string key, T value, int? expiryInMinutes, bool slidingExpiration = true) + { + return Task.FromResult(value); + } + + public Task GetOrCreateAsync(string key, Func getValue) + { + return Task.FromResult(getValue()); + } + + public Task GetOrCreateAsync(string key, Func getValue, int? expiryInMinutes, bool slidingExpiration = true) + { + return Task.FromResult(getValue()); + } + + public Task GetOrFetchAsync(string key, Func> getValue) + { + return getValue(); + } + + public Task GetOrFetchAsync(string key, Func> getValue, int? expiryInMinutes, bool slidingExpiration = true) + { + return getValue(); + } + + public Task FlushAll() + { + return Task.CompletedTask; + } + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor new file mode 100644 index 000000000..e02abfc9b --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor @@ -0,0 +1 @@ + diff --git a/LearningHub.Nhs.WebUI.BlazorClient/nuget.config.template b/LearningHub.Nhs.WebUI.BlazorClient/nuget.config.template new file mode 100644 index 000000000..dac496006 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/nuget.config.template @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.sln b/LearningHub.Nhs.WebUI.sln index c88094381..c152e2655 100644 --- a/LearningHub.Nhs.WebUI.sln +++ b/LearningHub.Nhs.WebUI.sln @@ -93,6 +93,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.Autom EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.Shared", "LearningHub.Nhs.Shared\LearningHub.Nhs.Shared.csproj", "{9F1B0470-E809-49FE-A6E8-152C7EBD012E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LearningHub.Nhs.WebUI.BlazorClient", "LearningHub.Nhs.WebUI.BlazorClient\LearningHub.Nhs.WebUI.BlazorClient.csproj", "{A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -365,6 +367,14 @@ Global {9F1B0470-E809-49FE-A6E8-152C7EBD012E}.Release|Any CPU.Build.0 = Release|Any CPU {9F1B0470-E809-49FE-A6E8-152C7EBD012E}.Release|x64.ActiveCfg = Release|Any CPU {9F1B0470-E809-49FE-A6E8-152C7EBD012E}.Release|x64.Build.0 = Release|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Debug|x64.Build.0 = Debug|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Release|Any CPU.Build.0 = Release|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Release|x64.ActiveCfg = Release|Any CPU + {A7DA82FE-A46C-47E9-8BD6-7FD7A8376CBA}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj index 345fff7db..01ab821eb 100644 --- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj +++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj @@ -109,7 +109,7 @@ - + @@ -179,6 +179,7 @@ + From 8167a971fb38a960c6353c92be7b6ba4292de015 Mon Sep 17 00:00:00 2001 From: Phil-NHS Date: Wed, 6 Aug 2025 15:38:18 +0100 Subject: [PATCH 3/8] TD-5888 Working when not using shared project --- .../Configuration/PublicSettings.cs | 19 +-- .../Helpers/FormattingHelper.cs | 61 +++++++ .../Helpers/MoodleHelper.cs | 115 +++++++++++++ .../Configuration/IPublicSettings.cs | 9 + .../LearningHub.Nhs.Shared.csproj | 4 +- .../Models/Search/SearchRequestViewModel.cs | 12 -- .../Services/ProviderService.cs | 2 +- .../Services/SearchService.cs | 7 +- .../LearningHub.Nhs.WebUI.BlazorClient.csproj | 29 ++-- ...ningHub.Nhs.WebUI.BlazorClient.csproj.user | 5 +- LearningHub.Nhs.WebUI.BlazorClient/Program.cs | 120 ++++++-------- .../Services/GenericAPIHttpClient.cs | 9 +- .../Services/WasmCacheServiceStub.cs | 2 +- .../TestDeleteMe/APITestDeleteME.razor | 100 +++++++++++ .../TestDeleteMe/FromShared/IAPIHttpClient.cs | 18 ++ .../FromShared/IFindwiseSettingsPublic.cs | 29 ++++ .../FromShared/ILearningHubHttpClient.cs | 22 +++ .../FromShared/ILearningHubHttpClientTest.cs | 22 +++ .../FromShared/IOpenAPIHttpClient.cs | 28 ++++ .../FromShared/IPublicSettings.cs | 37 +++++ .../FromShared/IUserAPIHttpClient.cs | 22 +++ .../TestDeleteMe/FromShared/PublicSettings.cs | 29 ++++ .../TestDeleteMe/HelloWorld.razor | 25 +++ .../_Imports.razor | 10 +- .../Configuration/Settings.cs | 8 +- .../Controllers/Api/BFFController.cs | 6 +- .../Controllers/SearchController.cs | 2 +- .../Helpers/UtilityHelper.cs | 156 +----------------- LearningHub.Nhs.WebUI/Program.cs | 5 +- .../Services/LearningHubHttpClient.cs | 2 +- .../Services/NLogLogLevelSwitcherService.cs | 127 ++++++++++++++ .../Startup/ServiceMappings.cs | 46 +++++- .../Views/Home/LandingPage.cshtml | 7 + .../Views/Home/_MyAccessedLearningTray.cshtml | 3 + .../Views/Search/_ResourceSearchResult.cshtml | 2 +- .../Shared/Tenant/LearningHub/_Layout.cshtml | 5 +- .../Views/_ViewImports.cshtml | 6 + global.json | 5 + 38 files changed, 834 insertions(+), 282 deletions(-) create mode 100644 LearningHub.Nhs.Shared/Helpers/FormattingHelper.cs create mode 100644 LearningHub.Nhs.Shared/Helpers/MoodleHelper.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs create mode 100644 LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor rename {LearningHub.Nhs.Shared => LearningHub.Nhs.WebUI}/Helpers/UtilityHelper.cs (68%) create mode 100644 LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs create mode 100644 global.json diff --git a/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs b/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs index c8607094f..b99948e99 100644 --- a/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs +++ b/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs @@ -15,17 +15,16 @@ public class PublicSettings : IPublicSettings { /// public string LearningHubApiUrl { get; set; } - - /// - public int ResourceSearchPageSize { get; set; } - - /// - public int CatalogueSearchPageSize { get; set; } - - /// - public int AllCatalogueSearchPageSize { get; set; } - + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// + /// Backend for Frontend (BFF) URL for the Learning Hub API accessed by samesite cookie and uses httpclients with bearers to access external apis. + /// + public string LearningHubApiBFFUrl { get; set; } /// public IFindwiseSettingsPublic FindwiseSettings { get; set; } + } } diff --git a/LearningHub.Nhs.Shared/Helpers/FormattingHelper.cs b/LearningHub.Nhs.Shared/Helpers/FormattingHelper.cs new file mode 100644 index 000000000..1afb7b464 --- /dev/null +++ b/LearningHub.Nhs.Shared/Helpers/FormattingHelper.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LearningHub.Nhs.Shared.Helpers +{ + public static class FormattingHelper + { + + /// + /// Returns a number of milliseconds converted into a duration string, such as "10 min 15 sec". Includes rounding to match the behaviour of the Azure Media Player. + /// + /// The number of milliseconds. + /// The duration string. + public static string GetDurationText(int durationInMilliseconds) + { + if (durationInMilliseconds > 0) + { + // Azure media player rounds duration to nearest second. e.g. 8:59.88 becomes 9:00. LH needs to match. + int nearestSecond = (int)Math.Round(((double)durationInMilliseconds) / 1000); + var duration = new TimeSpan(0, 0, nearestSecond); + string returnValue = string.Empty; + + // If duration greater than an hour, don't return the seconds part. + if (duration.Hours > 0) + { + returnValue = $"{duration.Hours} hr {duration.Minutes} min "; + + // Exclude "0 min" from the return value. + if (returnValue.EndsWith(" 0 min ")) + { + returnValue = returnValue.Replace("0 min ", string.Empty); + } + } + else + { + returnValue = $"{duration.Minutes} min {duration.Seconds} sec "; + + // Exclude "0 min" and "0 sec" from the return value. + if (returnValue.StartsWith("0 min ")) + { + returnValue = returnValue.Replace("0 min ", string.Empty); + } + + if (returnValue.EndsWith(" 0 sec ")) + { + returnValue = returnValue.Replace("0 sec ", string.Empty); + } + } + + return returnValue; + } + else + { + return string.Empty; + } + } + } +} diff --git a/LearningHub.Nhs.Shared/Helpers/MoodleHelper.cs b/LearningHub.Nhs.Shared/Helpers/MoodleHelper.cs new file mode 100644 index 000000000..b8d5b3b5d --- /dev/null +++ b/LearningHub.Nhs.Shared/Helpers/MoodleHelper.cs @@ -0,0 +1,115 @@ +using LearningHub.Nhs.Models.Enums; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LearningHub.Nhs.Shared.Helpers +{ + public static class MoodleHelper + { + /// TODO: Remove this method after adding to Moodle resource types to models project. + /// + /// Returns a prettified resource type name, suitable for display in the UI. Includes video/audio duration string. + /// + /// The resource type. + /// The media duration in milliseconds. + /// The resource type name, and duration if applicable. + public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnum resourceType, int? durationInMilliseconds = 0) + { + switch (resourceType) + { + case ResourceTypeEnum.Assessment: + return "Assessment"; + case ResourceTypeEnum.Article: + return "Article"; + case ResourceTypeEnum.Audio: + string durationText = FormattingHelper.GetDurationText(durationInMilliseconds ?? 0); + durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; + return "Audio" + durationText; + case ResourceTypeEnum.Equipment: + return "Equipment"; + case ResourceTypeEnum.Image: + return "Image"; + case ResourceTypeEnum.Scorm: + return "elearning"; + case ResourceTypeEnum.Video: + durationText = FormattingHelper.GetDurationText(durationInMilliseconds ?? 0); + durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; + return "Video" + durationText; + case ResourceTypeEnum.WebLink: + return "Web link"; + case ResourceTypeEnum.GenericFile: + return "File"; + case ResourceTypeEnum.Embedded: + return "Embedded"; + case ResourceTypeEnum.Case: + return "Case"; + case ResourceTypeEnum.Html: + return "HTML"; + case ResourceTypeEnum.Moodle: + return "Course"; + default: + return "File"; + } + } + + /// TODO: Remove this method after adding to Moodle resource types to models project. + /// + /// Findwise Moodle resource type dictionary. + /// + public static readonly Dictionary FindwiseResourceMoodleTypeDict = new Dictionary() + { + { "video", ResourceTypeEnum.Video }, + { "article", ResourceTypeEnum.Article }, + { "case", ResourceTypeEnum.Case }, + { "weblink", ResourceTypeEnum.WebLink }, + { "audio", ResourceTypeEnum.Audio }, + { "scorm", ResourceTypeEnum.Scorm }, + { "assessment", ResourceTypeEnum.Assessment }, + { "genericfile", ResourceTypeEnum.GenericFile }, + { "image", ResourceTypeEnum.Image }, + { "html", ResourceTypeEnum.Html }, + { "moodle", ResourceTypeEnum.Moodle }, + }; + + /// + /// Returns a prettified resource type name, suitable for display in the UI. Excludes video/audio duration string. + /// + /// The resource type. + /// The resource type name, and duration if applicable. + public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType) + { + switch (resourceType) + { + case ResourceTypeEnum.Assessment: + return "Assessment"; + case ResourceTypeEnum.Article: + return "Article"; + case ResourceTypeEnum.Audio: + return "Audio"; + case ResourceTypeEnum.Equipment: + return "Equipment"; + case ResourceTypeEnum.Image: + return "Image"; + case ResourceTypeEnum.Scorm: + return "elearning"; + case ResourceTypeEnum.Video: + return "Video"; + case ResourceTypeEnum.WebLink: + return "Web link"; + case ResourceTypeEnum.GenericFile: + return "File"; + case ResourceTypeEnum.Embedded: + return "Embedded"; + case ResourceTypeEnum.Case: + return "Case"; + case ResourceTypeEnum.Html: + return "HTML"; + default: + return "File"; + } + } + } +} diff --git a/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs b/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs index f81ef73af..5abd26aea 100644 --- a/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs +++ b/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs @@ -23,6 +23,15 @@ public interface IPublicSettings /// public string LearningHubApiUrl { get; set; } + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// + /// Gets or sets the LearningHubApiBFFUrl used to proxy via same domain cookie to the BFF LearningHubAPI calls. + /// + public string LearningHubApiBFFUrl { get; set; } + public IFindwiseSettingsPublic FindwiseSettings { get; set; } } } diff --git a/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj b/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj index 48ade5c7d..b46d3e846 100644 --- a/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj +++ b/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj @@ -7,7 +7,9 @@ + + @@ -15,5 +17,5 @@ - + diff --git a/LearningHub.Nhs.Shared/Models/Search/SearchRequestViewModel.cs b/LearningHub.Nhs.Shared/Models/Search/SearchRequestViewModel.cs index a59b832f9..f8b56cfd7 100644 --- a/LearningHub.Nhs.Shared/Models/Search/SearchRequestViewModel.cs +++ b/LearningHub.Nhs.Shared/Models/Search/SearchRequestViewModel.cs @@ -2,7 +2,6 @@ { using System.Collections.Generic; using System.ComponentModel.DataAnnotations; - using Microsoft.AspNetCore.Mvc;//qqqq /// /// Defines the . @@ -13,67 +12,56 @@ public class SearchRequestViewModel /// Gets or sets the search string. /// [Required(ErrorMessage = "Search text is required")] - [FromQuery] public string Term { get; set; } /// /// Gets or sets the filters. /// - [FromQuery] public IEnumerable Filters { get; set; } /// /// Gets or sets the sort item index. /// - [FromQuery] public int? Sortby { get; set; } /// /// Gets or sets the catalogue current page index. /// - [FromQuery] public int? CataloguePageIndex { get; set; } /// /// Gets or sets the resource current page index. /// - [FromQuery] public int? ResourcePageIndex { get; set; } /// /// Gets or sets the group id. /// - [FromQuery] public string GroupId { get; set; } /// /// Gets or sets a value indicating whether gets or sets the feedback submitted. /// - [FromQuery] public bool? FeedbackSubmitted { get; set; } /// /// Gets or sets the search id. /// - [FromQuery] public int? SearchId { get; set; } /// /// Gets or sets the catalogue id, when searching within a particular catalogue. /// - [FromQuery] public int? CatalogueId { get; set; } /// /// Gets or sets the resource access level id. /// - [FromQuery] public int? ResourceAccessLevelId { get; set; } /// /// Gets or sets the provider ids. /// - [FromQuery] public IEnumerable ProviderFilters { get; set; } } } \ No newline at end of file diff --git a/LearningHub.Nhs.Shared/Services/ProviderService.cs b/LearningHub.Nhs.Shared/Services/ProviderService.cs index a4d56ed47..614170184 100644 --- a/LearningHub.Nhs.Shared/Services/ProviderService.cs +++ b/LearningHub.Nhs.Shared/Services/ProviderService.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using LearningHub.Nhs.Caching; + using LearningHub.Nhs.Caching;//qqqq has aspnetcore in it using LearningHub.Nhs.Models.Provider; using LearningHub.Nhs.Shared.Interfaces.Http; using LearningHub.Nhs.Shared.Interfaces.Services; diff --git a/LearningHub.Nhs.Shared/Services/SearchService.cs b/LearningHub.Nhs.Shared/Services/SearchService.cs index 8d82ee59e..d98d6b34f 100644 --- a/LearningHub.Nhs.Shared/Services/SearchService.cs +++ b/LearningHub.Nhs.Shared/Services/SearchService.cs @@ -11,7 +11,6 @@ using LearningHub.Nhs.Shared.Interfaces.Http; using LearningHub.Nhs.Shared.Interfaces.Services; using LearningHub.Nhs.Shared.Models.Search; - using LearningHub.Nhs.WebUI.Helpers; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; @@ -170,10 +169,10 @@ public async Task PerformSearch(IPrincipal user, SearchRe { var filter = filters.Where(x => x.DisplayName == filteritem).FirstOrDefault(); - if (filter != null && UtilityHelper.FindwiseResourceMoodleTypeDict.ContainsKey(filter.DisplayName)) + if (filter != null && MoodleHelper.FindwiseResourceMoodleTypeDict.ContainsKey(filter.DisplayName)) { - var resourceTypeEnum = UtilityHelper.FindwiseResourceMoodleTypeDict[filter.DisplayName]; - var searchfilter = new SearchFilterModel() { DisplayName = UtilityHelper.GetPrettifiedResourceTypeNameMoodle(resourceTypeEnum), Count = filter.Count, Value = filteritem, Selected = searchRequest.Filters?.Contains(filter.DisplayName) ?? false }; + var resourceTypeEnum = MoodleHelper.FindwiseResourceMoodleTypeDict[filter.DisplayName]; + var searchfilter = new SearchFilterModel() { DisplayName = MoodleHelper.GetPrettifiedResourceTypeNameMoodle(resourceTypeEnum), Count = filter.Count, Value = filteritem, Selected = searchRequest.Filters?.Contains(filter.DisplayName) ?? false }; searchfilters.Add(searchfilter); } } diff --git a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj index ce506bf11..fd08600f9 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj +++ b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj @@ -1,17 +1,24 @@  + net8.0 enable enable - true - full + + - + + + + + @@ -27,27 +34,19 @@ - - - - - - - - - - - + + + \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user index 9ff5820a2..877a5e481 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user +++ b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj.user @@ -1,6 +1,9 @@  - https + IIS Local + + + ProjectDebugger \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs index 3aea91207..fd864d5f6 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs @@ -1,13 +1,17 @@ -// Microsoft namespaces - //using LearningHub.Nhs.Models.Entities; // Still required server side even if not used so components dont fail using Blazored.LocalStorage; -using LearningHub.Nhs.Caching; + +// qqqq Test try without aspentcore library contamination +//using LearningHub.Nhs.Caching; +//using LearningHub.Nhs.Shared.Configuration; +//using LearningHub.Nhs.Shared.Interfaces; +//using LearningHub.Nhs.Shared.Interfaces.Configuration; +//using LearningHub.Nhs.Shared.Interfaces.Http; +//using LearningHub.Nhs.Shared.Interfaces.Services; +//using LearningHub.Nhs.Shared.Services; using LearningHub.Nhs.WebUI.BlazorClient.Services; -using LearningHub.Nhs.Shared.Configuration; -using LearningHub.Nhs.Shared.Interfaces; -using LearningHub.Nhs.Shared.Services; +using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; @@ -25,23 +29,23 @@ using Serilog.Formatting.Compact; using Serilog.Settings.Configuration; using Serilog.Sinks.BrowserConsole; +using System; using TELBlazor.Components.Core.Configuration; using TELBlazor.Components.Core.Services.HelperServices; using TELBlazor.Components.OptionalImplementations.Core.Services.HelperServices; -using TELBlazor.Components.OptionalImplementations.Test.TestComponents.SearchExperiment; -using LearningHub.Nhs.Shared.Interfaces.Services; - - - +// qqqq should be loading the appsettings apparently var builder = WebAssemblyHostBuilder.CreateDefault(args); -var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; -builder.Configuration.AddJsonFile($"appsettings.{environment}.json", optional: false, reloadOnChange: true); +var http = new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }; +var env = builder.HostEnvironment.Environment; +using var envSettings = await http.GetStreamAsync($"appsettings.{env}.json"); -builder.Logging.ClearProviders(); +builder.Configuration.AddJsonStream(envSettings); +builder.Services.Configure(builder.Configuration.GetSection("Settings")); +builder.Logging.ClearProviders(); // Read default logging level from configuration var logLevelString = builder.Configuration["Serilog:MinimumLevel:Default"]; @@ -61,10 +65,6 @@ // Add Serilog to logging providers builder.Logging.AddSerilog(Log.Logger, dispose: true);//qqqq may not need dispose for client - - - - //for really bad fails try { @@ -78,73 +78,59 @@ }; }); - - builder.Services.AddBlazoredLocalStorage(); //could make our own caching with this client side ... but needs careful consideration of managing two sets of cache for pages of mixed mvc and blazor components + builder.Services.AddBlazoredLocalStorage(); - //this.findwiseSettings = findwiseSettings.Value; - //this.publicSettings = publicSettings.Value; - builder.Configuration.AddJsonFile($"appsettings.{environment}.json", optional: true); - builder.Services.Configure(builder.Configuration.GetSection("Settings")); - //!!!!! builder.Services.Configure(builder.Configuration.GetSection("Settings"));//qqqq we cannot do this in actuality there are security things inthsi - //Scoped because being consumed with storage where singleton doesnt survive mvc page teardown - //qqqq do we need it - //builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); - - // Register your BFF-pointing clients - - //builder.Services.AddHttpClient(client => { - // client.BaseAddress = new Uri("https://localhost:5001/bff/lh-web/"); // or whatever your BFF port is - //}); - - - //we want to do this - oh but it wont be in domain! - // it will be https://lh-web.dev.local/bff/ the api name so we need to set the name the same ... it doesnt need to be the same but may aswell - // the other local ones are https://lh-web.dev.local/api/ - - //"LearningHubUrl": "https://bff/lh-web.dev.local/", - //"ELfhHubUrl": "https://bff/test-portal.e-lfhtech.org.uk ", - //"LearningHubApiUrl": "https://bff/lh-api.dev.local/api/", - //"UserApiUrl": "https://bff/lh-userapi.dev.local/api/", - //"LearningHubAdminUrl": "https://bff/lh-admin.dev.local/", - - - //"LearningHubUrl": "https://lh-web.dev.local/", - //"ELfhHubUrl": "https://test-portal.e-lfhtech.org.uk ", - //"LearningHubApiUrl": "https://lh-api.dev.local/api/", - //"UserApiUrl": "https://lh-userapi.dev.local/api/", - //"LearningHubAdminUrl": "https://lh-admin.dev.local/", + /* qqqq + // "LearningHubApiUrl": "https://lh-api.dev.local/api/", + // "LearningHubApiBFFUrl": "https://bff/lh-api.dev.local/api/", + // IOptions webSettings, + // this.WebSettings.LearningHubApiUrl; + client.BaseAddress = new Uri(publicSettings.LearningHubApiBFFUrl); // or whatever your BFF port is + }); + */ + // Register your BFF - pointing clients + builder.Services.AddHttpClient((serviceProvider, client) => + { + IPublicSettings publicSettings = serviceProvider.GetRequiredService>().Value; + + // Log the URL to the console for debugging purposes. + // qqqq + Console.WriteLine($"[Configuration Log] Using Learning Hub API BFF URL: {publicSettings.LearningHubApiBFFUrl}"); + Console.WriteLine($"public settings: {publicSettings}"); + Uri apiUri = new Uri(publicSettings.LearningHubApiUrl); + string apiHost = apiUri.Host; + // qqqq may need forward slases + client.BaseAddress = new Uri($"{publicSettings.LearningHubApiBFFUrl}{apiHost}/"); // or whatever your BFF port is + }); - //builder.Services.AddHttpClient(client => { + //builder.Services.AddHttpClient(client => + //{ // client.BaseAddress = new Uri("https://localhost:5001/bff/lh-userapi/"); //}); - // LearningHubApiUrl -> //"LearningHubApiUrl": "https://lh-web.dev.local/bff/Catalogue/GetLatestCatalogueAccessRequest/500/lh-api.dev.local/api/", --> //"LearningHubApiUrl": "https://lh-api.dev.local/api/", + //// LearningHubApiUrl-> //"LearningHubApiUrl": "https://lh-web.dev.local/bff/Catalogue/GetLatestCatalogueAccessRequest/500/lh-api.dev.local/api/", --> //"LearningHubApiUrl": "https://lh-api.dev.local/api/", - // qqqq put back in - //builder.Services.AddHttpClient(client => { + //builder.Services.AddHttpClient(client => + //{ // client.BaseAddress = new Uri("https://lh-web.dev.local/bff/lh-api.dev.local/"); // or whatever your BFF port is //}); - //// //"UserApiUrl": "https://bff/lh-userapi.dev.local/api/", --> //"UserApiUrl": "https://lh-userapi.dev.local/api/", - //builder.Services.AddHttpClient(client => { + //// "UserApiUrl": "https://bff/lh-userapi.dev.local/api/", --> //"UserApiUrl": "https://lh-userapi.dev.local/api/", + //builder.Services.AddHttpClient(client => + //{ // client.BaseAddress = new Uri("https://lh-web.dev.local/bff/lh-userapi.dev.local/"); //}); + builder.Services.AddScoped(sp => levelSwitch); builder.Services.AddScoped(); - builder.Services.AddScoped(); // had to change provider not to use it previously trying again - builder.Services.AddScoped(); - - - - //qqqq Register IOptions - requires manual binding in WASM - // --> qqqq MONDAY Important: In Blazor WASM, IOptions works only if the configuration is available at runtime.That means you must ensure that your appsettings.json or other configuration is correctly loaded into builder.Configuration. - - + // qqqq will need back in post removing asp.net shared + //builder.Services.AddScoped(); // had to change provider not to use it previously trying again + //builder.Services.AddScoped(); await builder.Build().RunAsync(); } diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs index d200b2288..c9e05fdf0 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs @@ -1,8 +1,11 @@ -using LearningHub.Nhs.Shared.Interfaces.Http; +// qqqq using LearningHub.Nhs.Shared.Interfaces.Http; -namespace LearningHub.Nhs.WebUI.BlazorClient.Services +using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared; + +//namespace LearningHub.Nhs.WebUI.BlazorClient.Services // qqqq weird suggestion need to shame namespace!!?? +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared { - public class GenericAPIHttpClient : IAPIHttpClient, ILearningHubHttpClient, IUserApiHttpClient // Implementing multiple interfaces + public class GenericAPIHttpClient : IAPIHttpClient, ILearningHubHttpClient, IUserApiHttpClient, ILearningHubHttpClientTest // Implementing multiple interfaces { private readonly HttpClient _httpClient; // Private field to hold the injected HttpClient diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs index 67836f39f..b8d5239ca 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs @@ -1,4 +1,4 @@ -using LearningHub.Nhs.Caching; +using LearningHub.Nhs.Caching;// has aspnetcore in it qqqq we just need the interface namespace LearningHub.Nhs.WebUI.BlazorClient.Services { diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor new file mode 100644 index 000000000..bc90b9c40 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor @@ -0,0 +1,100 @@ +@using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared @*remove later qqqq*@ + +@*@using Microsoft.AspNetCore.Components;qqqq*@ +@inject ILearningHubHttpClientTest LearningHubBFFHttpClient +@inherits TELBlazor.Components.Core.TELComponentBase +@*we are hiding what is in the base class by doing the logger this way but the telbutton does it to so it needs sorting*@ +
+ + +
+ +@code { + string ApiRoute = "Catalogue/GetLatestCatalogueAccessRequest/43"; // Default route 500 + + + + protected override void OnInitialized() + { + base.OnInitialized(); // Call the base method + Logger.LogInformation("Serilogging"); + + + Logger.LogInformation( + "API Test Component initialized with default route: {Route}", + ApiRoute + ); + + Logger.LogInformation("!!!!!!!!!!!!!!!!!!!!!!!!! Base Component"); + } + + private async Task CallApi() + { + try + { + + Logger.LogInformation("Base Component"); + var httpClient = await LearningHubBFFHttpClient.GetClientAsync(); + + Logger.LogInformation("📡 BaseAddress should be https://lh-web.dev.local/bff/lh-api.dev.local/ . HttpClient BaseAddress: {BaseAddress}", httpClient.BaseAddress?.ToString()); + Logger.LogInformation($"Logger: Calling via the bff this api route: {ApiRoute}"); + Logger.LogInformation("📡 Target: {TargetUrl}", "https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500"); + // Assuming httpClient.BaseAddress is set + string fullUrl = new Uri(httpClient.BaseAddress, ApiRoute).ToString(); + Logger.LogInformation("Making request to: {FullUrl}", fullUrl); + + // Now use standard HttpClient methods + var response = await httpClient.GetAsync(ApiRoute); //qqqq here it doesnt seem to be using base address + string responseContent = await response.Content.ReadAsStringAsync(); + + Logger.LogInformation("API Response - Status: {Status}, Content: {Content}", + response.StatusCode, responseContent); + + /* qqqq + * // https://bff/lh-api.dev.local/api/Catalogue/GetLatestCatalogueAccessRequest/500 - wrong + * // -> think need // https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500 + + + + + // "LearningHubApiUrl": "https://lh-api.dev.local/api/", + // "LearningHubApiBFFUrl": "https://bff/lh-api.dev.local/api/", + // IOptions webSettings, + // this.WebSettings.LearningHubApiUrl; + client.BaseAddress = new Uri(publicSettings.LearningHubApiBFFUrl); // or whatever your BFF port is + }); + */ + // Register your BFF-pointing clients + // var client = await HttpClient.GetClientAsync(); + // Console.WriteLine("ConsoleWriteline:APIClient BaseAddress: {Route}", client.BaseAddress); + // Logger.LogInformation("APIClient BaseAddress: {Route}", client.BaseAddress); + // var response = await client.GetAsync(ApiRoute); + // string responseContent = await response.Content.ReadAsStringAsync(); + // int statusCode = (int)response.StatusCode; + + // if (response.IsSuccessStatusCode) + // { + // Console.WriteLine("ConsoleWriteline: API call successful! Status: {StatusCode}, Content: {Content}", statusCode, responseContent); + // Logger.LogInformation("API call successful! Status: {StatusCode}, Content: {Content}", statusCode, responseContent); + // } + // else + // { + // Console.WriteLine("ConsoleWriteline: API call failed! Status: {StatusCode}, Error Content: {ErrorContent}", statusCode, responseContent); + // Logger.LogError("API call failed! Status: {StatusCode}, Error Content: {ErrorContent}", statusCode, responseContent); + // } + + + // await Task.Delay(1000); + // StateHasChanged(); + + } + catch (Exception ex) + { + // FIX 5: Log exceptions with ILogger. + Logger.LogCritical("in exception"); + Logger.LogCritical(ex,"argh"); + Logger.LogError(ex, "An error occurred during API call to route: {Route}", ApiRoute); + + } + } +} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs new file mode 100644 index 000000000..8c19dd22f --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs @@ -0,0 +1,18 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Represents an HTTP client for a specific API. + /// + public interface IAPIHttpClient + { + /// + /// Gets the configured for the API. + /// + Task GetClientAsync(); + + /// + /// Gets the base URL of the API. + /// + string ApiUrl { get; } + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs new file mode 100644 index 000000000..4299dee7e --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs @@ -0,0 +1,29 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Represents configuration values related to Findwise search that are safe to expose + /// to client-side applications or public-facing APIs. + /// + /// + /// This includes non-sensitive values such as page sizes for different types of search results. + /// It does not contain any secure credentials or internal service configuration. + /// + /// + public interface IFindwiseSettingsPublic + { + /// + /// Gets or sets the page size for resource search results. + /// + public int ResourceSearchPageSize { get; set; } + + /// + /// Gets or sets the CatalogueSearchPageSize. + /// + public int CatalogueSearchPageSize { get; set; } + + /// + /// Gets or sets the AllCatalogueSearchPageSize. + /// + public int AllCatalogueSearchPageSize { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs new file mode 100644 index 000000000..529f26ccd --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs @@ -0,0 +1,22 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Marker interface for the LearningHub API HttpClient. + /// + /// + /// Inherits from to enable + /// dependency injection of a specific implementation configured with + /// different API endpoints or settings specific to LH API. + /// + /// + /// + /// Currently, this interface is empty and used solely to differentiate implementations + /// that connect to different endpoints via configuration, but it may be extended in the future + /// with LearningHub-specific functionality or properties. + /// + /// + public interface ILearningHubHttpClient : IAPIHttpClient + { + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs new file mode 100644 index 000000000..65e99c06b --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs @@ -0,0 +1,22 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Marker interface for the LearningHub API HttpClient. + /// + /// + /// Inherits from to enable + /// dependency injection of a specific implementation configured with + /// different API endpoints or settings specific to LH API. + /// + /// + /// + /// Currently, this interface is empty and used solely to differentiate implementations + /// that connect to different endpoints via configuration, but it may be extended in the future + /// with LearningHub-specific functionality or properties. + /// + /// + public interface ILearningHubHttpClientTest : IAPIHttpClient + { + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs new file mode 100644 index 000000000..6388090e4 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Marker interface for the IOpenAPIHttpClient API HttpClient. + /// + /// + /// Inherits from to enable + /// dependency injection of a specific implementation configured with + /// a openapi-related API endpoint or settings. + /// + /// + /// + /// This interface is currently empty and used solely to differentiate + /// implementations that connect to different endpoints via configuration. + /// It may be extended in the future with user-specific functionality or properties. + /// + /// + public interface IOpenApiHttpClient : IAPIHttpClient + { + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs new file mode 100644 index 000000000..73a9f81a9 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs @@ -0,0 +1,37 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Defines a contract for configuration data that is non-sensitive and safe to expose publicly + /// + /// + /// This interface exposes only data that is safe to be publicly consumed or shared, + /// such as API endpoint URLs or non-sensitive configuration values. + /// It explicitly excludes any private or sensitive information (e.g., authentication tokens, + /// credentials, or secret keys), which should be handled via separate interfaces or services. + /// + /// + /// + /// The data provided by this interface can be safely used in frontend technologies, + /// such as Blazor WebAssembly, JavaScript frameworks, or other client-side applications, + /// without risking exposure of sensitive information. + /// + /// + public interface IPublicSettings + { + /// + /// Gets or sets the LearningHubApiUrl. + /// + public string LearningHubApiUrl { get; set; } + + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// + /// Gets or sets the LearningHubApiBFFUrl used to proxy via same domain cookie to the BFF LearningHubAPI calls. + /// + public string LearningHubApiBFFUrl { get; set; } + + public IFindwiseSettingsPublic FindwiseSettings { get; set; } + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs new file mode 100644 index 000000000..1afee3f81 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs @@ -0,0 +1,22 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Marker interface for the User API HttpClient. + /// + /// + /// Inherits from to enable + /// dependency injection of a specific implementation configured with + /// a user-related API endpoint or settings. + /// + /// + /// + /// This interface is currently empty and used solely to differentiate + /// implementations that connect to different endpoints via configuration. + /// It may be extended in the future with user-specific functionality or properties. + /// + /// + public interface IUserApiHttpClient : IAPIHttpClient + { + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs new file mode 100644 index 000000000..bc2f3a645 --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs @@ -0,0 +1,29 @@ +namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +{ + /// + /// Represents configuration values that are safe to expose to clientside frontend applications + /// (such as Blazor WebAssembly) or public-facing APIs. + /// + /// + /// Implements and contains only non-sensitive, non-secret + /// values such as public API endpoints and pagination settings. This separation ensures + /// that secure or private configuration data is not inadvertently exposed to clients. + /// + /// + public class PublicSettings : IPublicSettings + { + /// + public string LearningHubApiUrl { get; set; } + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// + /// Backend for Frontend (BFF) URL for the Learning Hub API accessed by samesite cookie and uses httpclients with bearers to access external apis. + /// + public string LearningHubApiBFFUrl { get; set; } + /// + public IFindwiseSettingsPublic FindwiseSettings { get; set; } + + } +} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor new file mode 100644 index 000000000..6550626dd --- /dev/null +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor @@ -0,0 +1,25 @@ +@inherits TELBlazor.Components.Core.TELComponentBase +@inject ILogger Logger +

Hello Blazor!

+

If you see this and the console message, Blazor WASM code is running.

+ +

Button has been clicked: @clickCount times.

+ + +@code { + private int clickCount = 0; // Initialize a counter + protected override void OnInitialized() + { + base.OnInitialized(); // Call the base method + Console.WriteLine("-----> SimpleTest Component Initialized! If you see this, Blazor WASM code is executing."); + } + + private void HandleButtonClick() + { + // This C# code will run when the button is clicked. + Console.WriteLine("----> Button was clicked! C# method executed."); + + clickCount++; + Logger.LogWarning("serilog in simple"); + } +} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor index e02abfc9b..c7837620c 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor +++ b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor @@ -1 +1,9 @@ - +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using LearningHub.Nhs.WebUI.BlazorClient + +@*qqqq may not be needed try dropping and see logging still works*@ +@using Microsoft.AspNetCore.Components; +@using Microsoft.Extensions.Logging; +@using TELBlazor.Components.Core.Configuration; \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Configuration/Settings.cs b/LearningHub.Nhs.WebUI/Configuration/Settings.cs index 30f427cb4..b20d175b1 100644 --- a/LearningHub.Nhs.WebUI/Configuration/Settings.cs +++ b/LearningHub.Nhs.WebUI/Configuration/Settings.cs @@ -2,12 +2,13 @@ namespace LearningHub.Nhs.WebUI.Configuration { using System; using LearningHub.Nhs.Shared.Configuration; + using LearningHub.Nhs.Shared.Interfaces.Configuration; using LearningHub.Nhs.WebUI.Models.Contribute; /// /// Defines the . /// - public class Settings + public class Settings : IPublicSettings { /// /// Initializes a new instance of the class. @@ -32,6 +33,9 @@ public Settings() /// public string LearningHubApiUrl { get; set; } + /// + public string LearningHubApiBFFUrl { get; set; } + /// /// Gets or sets the OpenApiUrl. /// @@ -255,7 +259,7 @@ public Settings() /// /// Gets or sets the FindwiseSettings. /// - public FindwiseSettingsPublic FindwiseSettings { get; set; } = new FindwiseSettingsPublic(); + public IFindwiseSettingsPublic FindwiseSettings { get; set; } = new FindwiseSettingsPublic(); /// /// Gets or sets the MediaKindSettings. diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs index c5f082d75..da3f79fd4 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs @@ -23,7 +23,7 @@ /// See confluence for more details on the BFF pattern and how to use this controller. /// /// The authorize same site cookie is used for security between client and server. API calls relying on policys such as AuthorizeOrCallFromLH may not be proxied as they require the Authorization header to be present. - [Authorize] + [Authorize] // QQQQ !!!! PUTBACKIN !!!!!!!!!!!!!!!!!! [Route("bff/{apiName}/{**path}")] [ApiController] public class BFFController : BaseApiController @@ -78,6 +78,8 @@ public async Task ProxyRequest(string apiName, string path) string sanitizedPath = path?.Trim('/').ToLowerInvariant() ?? string.Empty; string sanitizedApiName = apiName?.Trim('/').ToLowerInvariant() ?? string.Empty; + // https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500 + // qqqq lh-api.dev.local getting this IAPIHttpClient apiClient; try { @@ -102,6 +104,7 @@ public async Task ProxyRequest(string apiName, string path) if (!this.IsPathAllowed(sanitizedPath)) { + // qqqq "catalogue/getlatestcatalogueaccessrequest/500" return this.Forbid("This path is not allowed via BFF proxy."); } @@ -239,6 +242,7 @@ private bool IsPathAllowed(string path) } // Check whitelist + // qqqqq catalogue/ vs "catalogue/getlatestcatalogueaccessrequest/500" return this.bffPathValidationOptions.Value.AllowedPathPrefixes.Any(prefix => normalizedPath.StartsWith(prefix.ToLowerInvariant())); } } diff --git a/LearningHub.Nhs.WebUI/Controllers/SearchController.cs b/LearningHub.Nhs.WebUI/Controllers/SearchController.cs index cada3e014..1438a7ba4 100644 --- a/LearningHub.Nhs.WebUI/Controllers/SearchController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/SearchController.cs @@ -62,7 +62,7 @@ public SearchController( /// filter applied. /// The actionResult. [HttpGet("results")] - public async Task Index(SearchRequestViewModel search, bool noSortFilterError = false, bool emptyFeedbackError = false, bool filterApplied = false) + public async Task Index([FromQuery] SearchRequestViewModel search, bool noSortFilterError = false, bool emptyFeedbackError = false, bool filterApplied = false) { search.SearchId ??= 0; search.GroupId = !string.IsNullOrWhiteSpace(search.GroupId) && Guid.TryParse(search.GroupId, out Guid groupId) ? groupId.ToString() : Guid.NewGuid().ToString(); diff --git a/LearningHub.Nhs.Shared/Helpers/UtilityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs similarity index 68% rename from LearningHub.Nhs.Shared/Helpers/UtilityHelper.cs rename to LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs index bdb41972c..515786d09 100644 --- a/LearningHub.Nhs.Shared/Helpers/UtilityHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs @@ -33,25 +33,6 @@ public static class UtilityHelper { "html", ResourceTypeEnum.Html }, }; - /// TODO: Remove this method after adding to Moodle resource types to models project. - /// - /// Findwise Moodle resource type dictionary. - /// - public static readonly Dictionary FindwiseResourceMoodleTypeDict = new Dictionary() - { - { "video", ResourceTypeEnum.Video }, - { "article", ResourceTypeEnum.Article }, - { "case", ResourceTypeEnum.Case }, - { "weblink", ResourceTypeEnum.WebLink }, - { "audio", ResourceTypeEnum.Audio }, - { "scorm", ResourceTypeEnum.Scorm }, - { "assessment", ResourceTypeEnum.Assessment }, - { "genericfile", ResourceTypeEnum.GenericFile }, - { "image", ResourceTypeEnum.Image }, - { "html", ResourceTypeEnum.Html }, - { "moodle", ResourceTypeEnum.Moodle }, - }; - /// /// The FormatTwitterDate. /// @@ -139,51 +120,7 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType case ResourceTypeEnum.Article: return "Article"; case ResourceTypeEnum.Audio: - string durationText = GetDurationText(durationInMilliseconds ?? 0); - durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; - return "Audio" + durationText; - case ResourceTypeEnum.Equipment: - return "Equipment"; - case ResourceTypeEnum.Image: - return "Image"; - case ResourceTypeEnum.Scorm: - return "elearning"; - case ResourceTypeEnum.Video: - durationText = GetDurationText(durationInMilliseconds ?? 0); - durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; - return "Video" + durationText; - case ResourceTypeEnum.WebLink: - return "Web link"; - case ResourceTypeEnum.GenericFile: - return "File"; - case ResourceTypeEnum.Embedded: - return "Embedded"; - case ResourceTypeEnum.Case: - return "Case"; - case ResourceTypeEnum.Html: - return "HTML"; - default: - return "File"; - } - } - - /// TODO: Remove this method after adding to Moodle resource types to models project. - /// - /// Returns a prettified resource type name, suitable for display in the UI. Includes video/audio duration string. - /// - /// The resource type. - /// The media duration in milliseconds. - /// The resource type name, and duration if applicable. - public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnum resourceType, int? durationInMilliseconds = 0) - { - switch (resourceType) - { - case ResourceTypeEnum.Assessment: - return "Assessment"; - case ResourceTypeEnum.Article: - return "Article"; - case ResourceTypeEnum.Audio: - string durationText = GetDurationText(durationInMilliseconds ?? 0); + string durationText = FormattingHelper.GetDurationText(durationInMilliseconds ?? 0); durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; return "Audio" + durationText; case ResourceTypeEnum.Equipment: @@ -193,7 +130,7 @@ public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnum resour case ResourceTypeEnum.Scorm: return "elearning"; case ResourceTypeEnum.Video: - durationText = GetDurationText(durationInMilliseconds ?? 0); + durationText = FormattingHelper.GetDurationText(durationInMilliseconds ?? 0); durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; return "Video" + durationText; case ResourceTypeEnum.WebLink: @@ -206,100 +143,11 @@ public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnum resour return "Case"; case ResourceTypeEnum.Html: return "HTML"; - case ResourceTypeEnum.Moodle: - return "Course"; default: return "File"; } } - /// - /// Returns a prettified resource type name, suitable for display in the UI. Excludes video/audio duration string. - /// - /// The resource type. - /// The resource type name, and duration if applicable. - public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType) - { - switch (resourceType) - { - case ResourceTypeEnum.Assessment: - return "Assessment"; - case ResourceTypeEnum.Article: - return "Article"; - case ResourceTypeEnum.Audio: - return "Audio"; - case ResourceTypeEnum.Equipment: - return "Equipment"; - case ResourceTypeEnum.Image: - return "Image"; - case ResourceTypeEnum.Scorm: - return "elearning"; - case ResourceTypeEnum.Video: - return "Video"; - case ResourceTypeEnum.WebLink: - return "Web link"; - case ResourceTypeEnum.GenericFile: - return "File"; - case ResourceTypeEnum.Embedded: - return "Embedded"; - case ResourceTypeEnum.Case: - return "Case"; - case ResourceTypeEnum.Html: - return "HTML"; - default: - return "File"; - } - } - - /// - /// Returns a number of milliseconds converted into a duration string, such as "10 min 15 sec". Includes rounding to match the behaviour of the Azure Media Player. - /// - /// The number of milliseconds. - /// The duration string. - public static string GetDurationText(int durationInMilliseconds) - { - if (durationInMilliseconds > 0) - { - // Azure media player rounds duration to nearest second. e.g. 8:59.88 becomes 9:00. LH needs to match. - int nearestSecond = (int)Math.Round(((double)durationInMilliseconds) / 1000); - var duration = new TimeSpan(0, 0, nearestSecond); - string returnValue = string.Empty; - - // If duration greater than an hour, don't return the seconds part. - if (duration.Hours > 0) - { - returnValue = $"{duration.Hours} hr {duration.Minutes} min "; - - // Exclude "0 min" from the return value. - if (returnValue.EndsWith(" 0 min ")) - { - returnValue = returnValue.Replace("0 min ", string.Empty); - } - } - else - { - returnValue = $"{duration.Minutes} min {duration.Seconds} sec "; - - // Exclude "0 min" and "0 sec" from the return value. - if (returnValue.StartsWith("0 min ")) - { - returnValue = returnValue.Replace("0 min ", string.Empty); - } - - if (returnValue.EndsWith(" 0 sec ")) - { - returnValue = returnValue.Replace("0 sec ", string.Empty); - } - } - - return returnValue; - } - else - { - return string.Empty; - } - } - /// /// Returns a string containing either the authoredBy or organisation string, or a combination of both if present. /// diff --git a/LearningHub.Nhs.WebUI/Program.cs b/LearningHub.Nhs.WebUI/Program.cs index e6540a821..34013d03a 100644 --- a/LearningHub.Nhs.WebUI/Program.cs +++ b/LearningHub.Nhs.WebUI/Program.cs @@ -87,7 +87,6 @@ app.UseAuthorization(); app.UseMiddleware(); - app.UseStaticFiles(); app.Map(TimezoneInfoMiddleware.TimezoneInfoUrl, b => b.UseMiddleware()); @@ -114,9 +113,7 @@ app.MapRazorComponents() .AddInteractiveServerRenderMode() .AddInteractiveWebAssemblyRenderMode() - - // .AddAdditionalAssemblies(typeof(LearningHub.Nhs.WebUI.BlazorComponents._Imports).Assembly) // qqqq later - // .AddAdditionalAssemblies(typeof(LearningHub.Nhs.WebUI.BlazorClient._Imports).Assembly); qqqq later + .AddAdditionalAssemblies(typeof(LearningHub.Nhs.WebUI.BlazorClient._Imports).Assembly) .AddAdditionalAssemblies(typeof(TELBlazor.Components._Imports).Assembly); app.Run(); diff --git a/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs b/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs index 9af95a1e6..de4613295 100644 --- a/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs +++ b/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs @@ -12,7 +12,7 @@ /// /// The learning hub http client. /// - public class LearningHubHttpClient : BaseHttpClient, ILearningHubHttpClient + public class LearningHubHttpClient : BaseHttpClient, ILearningHubHttpClient // qqqq { /// /// Initializes a new instance of the class. diff --git a/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs b/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs new file mode 100644 index 000000000..9772556f3 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs @@ -0,0 +1,127 @@ +namespace LearningHub.Nhs.WebUI.Services +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Threading.Tasks; + using Blazored.LocalStorage; + using Microsoft.Extensions.Logging; + using TELBlazor.Components.Core.Models.Logging; + using TELBlazor.Components.Core.Services.HelperServices; + + // qqqq this file needs completely reviewing + + /// + /// Provides functionality for managing log levels in applications using NLog. + /// + /// This service implements the interface to provide log + /// level management. Note that NLog does not support runtime log level switching in WASM environments. As a result, + /// methods in this service primarily serve to fulfill the interface contract and provide default + /// behaviors. + public class NLogLogLevelSwitcherService : ILogLevelSwitcherService + { + private const string LogLevelKey = "logLevel"; + private readonly ILogger logger; + private readonly ILocalStorageService localStorage; + + /// + /// Initializes a new instance of the class. + /// + /// The local storage service. + /// The logger instance. + public NLogLogLevelSwitcherService(ILocalStorageService localStorage, ILogger logger) + { + this.localStorage = localStorage; + this.logger = logger; + } + + /// + public bool IsInitialized { get; set; } = false; + + /// + public async Task InitializeLogLevelFromAsyncSourceIfAvailable() + { + // NLog does not support runtime level switching in WASM + // Here only to mirror the interface + this.logger.LogInformation("NLog does not support dynamic runtime log level switching."); + await Task.CompletedTask; + } + + /// + public List GetAvailableLogLevels() => + Enum.GetNames(typeof(LogLevel)).ToList(); + + /// + public string GetCurrentLogLevel() + { + this.logger.LogInformation("Returning default log level (NLog does not support querying runtime level)."); + return "Information"; + } + + /// + public string SetLogLevel(string level) + { + // if (string.IsNullOrWhiteSpace(level)) + // { + // _logger.LogWarning("Log level was null or empty."); + // return GetCurrentLogLevel(); + // } + // if (!Enum.TryParse(level, true, out var parsedLevel)) + // { + // _logger.LogWarning("Invalid log level: {Level}", level); + // return GetCurrentLogLevel(); + // } + this.logger.LogInformation("Requested to change log level to {Level}, but NLog does not support runtime changes in WASM.", level); + this.LogAllLevels("After 'Change'"); + + _ = this.StoreLogLevelWithTimestamp(level); // Fire and forget + return this.GetCurrentLogLevel(); + } + + private void LogAllLevels(string phase) + { + this.logger.LogTrace("[{Phase}] TRACE log", phase); + this.logger.LogDebug("[{Phase}] DEBUG log", phase); + this.logger.LogInformation("[{Phase}] INFO log", phase); + this.logger.LogWarning("[{Phase}] WARN log", phase); + this.logger.LogError("[{Phase}] ERROR log", phase); + this.logger.LogCritical("[{Phase}] CRITICAL log", phase); + } + + private async Task StoreLogLevelWithTimestamp(string level) + { + try + { + var newItem = new LocalStorageLogLevel + { + Level = level, + Expires = DateTime.UtcNow.AddHours(24), + }; + + await this.localStorage.SetItemAsync(LogLevelKey, newItem); + } + catch (Exception ex) + { + this.logger.LogError(ex, "Error storing log level to local storage."); + } + } + + // private async Task GetStoredLogLevelWithExpiration() + // { + // try + // { + // var storedItem = await _localStorage.GetItemAsync(LogLevelKey); + // if (storedItem == null || DateTime.UtcNow > storedItem.Expires) + // { + // await _localStorage.RemoveItemAsync(LogLevelKey); + // return null; + // } + // return storedItem.Level; + // } + // catch + // { + // return null; + // } + // } + } +} diff --git a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs index 50d52eaae..300b39c02 100644 --- a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs +++ b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs @@ -1,6 +1,8 @@ namespace LearningHub.Nhs.WebUI.Startup { + using System; using System.Net.Http; + using Blazored.LocalStorage; using GDS.MultiPageFormData; using LearningHub.Nhs.Models.OpenAthens; using LearningHub.Nhs.Services; @@ -18,6 +20,9 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using TELBlazor.Components.Core.Configuration; + using TELBlazor.Components.Core.Services.HelperServices; + using TELBlazor.Components.OptionalImplementations.Test.TestComponents.SearchExperiment; /// /// The service mappings. @@ -43,6 +48,15 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }); + // qqqq remove test + services.AddHttpClient() + .ConfigurePrimaryHttpMessageHandler( + () => new HttpClientHandler + { + ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, + }); + services.AddHttpClient() .ConfigurePrimaryHttpMessageHandler( () => new HttpClientHandler @@ -85,7 +99,13 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon // Config services.Configure(configuration.GetSection("OpenAthensScopes")); - services.Configure(configuration.GetSection(BFFPathValidationOptions.SectionName)); + services.Configure(configuration.GetSection("Settings:" + BFFPathValidationOptions.SectionName)); // qqqq + + // Blazor + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddCircuitOptions(opt => opt.DetailedErrors = true) + .AddInteractiveWebAssemblyComponents(); // Learning Hub Services services.AddTransient(); @@ -132,6 +152,30 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon services.AddScoped(); services.AddScoped(); services.AddScoped(); + + // + + // + // Future candidates for DI collection + services.AddBlazoredLocalStorage(); + services.AddSingleton(provider => + { + return new TELBlazorBaseComponentConfiguration + { + JSEnabled = true, // qqqq may need to implement as do from prototype if lh doesnt have a way + + // HostType = $"{builder.Configuration["Properties:Environment"]} {builder.Configuration["Properties:Application"]}" + // qqqq back to this one + HostType = $"{configuration["Properties:Environment"]} {configuration["Properties:Application"]}", + + // HostType = "Server", + }; + }); + + services.AddScoped(); + + // services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + // qqqq services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(configuration["Settings:LearningHubWebUiUrl"]) }); } } } diff --git a/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml b/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml index 3a681c901..4ca7e15b3 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml @@ -37,6 +37,13 @@ Sign up, explore and learn + + +
diff --git a/LearningHub.Nhs.WebUI/Views/Home/_MyAccessedLearningTray.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_MyAccessedLearningTray.cshtml index 47cf33901..0e663b5ac 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/_MyAccessedLearningTray.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/_MyAccessedLearningTray.cshtml @@ -37,7 +37,10 @@ }

My accessed learning

+ +
public string LearningHubApiUrl { get; set; } + /// + /// Gets or sets the UserApiUrl. + /// + public string UserApiUrl { get; set; } + /// /// Gets or sets the OpenApiUrl. /// diff --git a/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj b/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj index b46d3e846..11a4de7fa 100644 --- a/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj +++ b/LearningHub.Nhs.Shared/LearningHub.Nhs.Shared.csproj @@ -7,15 +7,15 @@ - - - - + + - - + + + + diff --git a/LearningHub.Nhs.Shared/Services/ProviderService.cs b/LearningHub.Nhs.Shared/Services/ProviderService.cs index 614170184..a4d56ed47 100644 --- a/LearningHub.Nhs.Shared/Services/ProviderService.cs +++ b/LearningHub.Nhs.Shared/Services/ProviderService.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - using LearningHub.Nhs.Caching;//qqqq has aspnetcore in it + using LearningHub.Nhs.Caching; using LearningHub.Nhs.Models.Provider; using LearningHub.Nhs.Shared.Interfaces.Http; using LearningHub.Nhs.Shared.Interfaces.Services; diff --git a/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs b/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs index 7123184aa..373445cf1 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs @@ -1,10 +1,10 @@ -using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Options; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; +using LearningHub.Nhs.Shared.Configuration; namespace LearningHub.Nhs.WebUI.BlazorClient.DI diff --git a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj index fd08600f9..61082b1c0 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj +++ b/LearningHub.Nhs.WebUI.BlazorClient/LearningHub.Nhs.WebUI.BlazorClient.csproj @@ -1,22 +1,22 @@  - net8.0 enable enable - - + + + + true + full - + + - @@ -41,12 +41,15 @@ - - - + - --> + \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs index b8079ef28..9b494c66a 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs @@ -3,17 +3,14 @@ using Blazored.LocalStorage; using LearningHub.Nhs.WebUI.BlazorClient.DI; - -// qqqq Test try without aspentcore library contamination -//using LearningHub.Nhs.Caching; -//using LearningHub.Nhs.Shared.Configuration; -//using LearningHub.Nhs.Shared.Interfaces; -//using LearningHub.Nhs.Shared.Interfaces.Configuration; -//using LearningHub.Nhs.Shared.Interfaces.Http; -//using LearningHub.Nhs.Shared.Interfaces.Services; -//using LearningHub.Nhs.Shared.Services; +using LearningHub.Nhs.Caching; +using LearningHub.Nhs.Shared.Configuration; +using LearningHub.Nhs.Shared.Interfaces; +using LearningHub.Nhs.Shared.Interfaces.Configuration; +using LearningHub.Nhs.Shared.Interfaces.Http; +using LearningHub.Nhs.Shared.Interfaces.Services; +using LearningHub.Nhs.Shared.Services; using LearningHub.Nhs.WebUI.BlazorClient.Services; -using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; @@ -36,9 +33,8 @@ using TELBlazor.Components.Core.Services.HelperServices; using TELBlazor.Components.OptionalImplementations.Core.Services.HelperServices; -// qqqq should be loading the appsettings apparently -var builder = WebAssemblyHostBuilder.CreateDefault(args); +var builder = WebAssemblyHostBuilder.CreateDefault(args); var http = new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }; var env = builder.HostEnvironment.Environment; @@ -84,7 +80,7 @@ // Register your BFF using httpclient ILearningHubHttpClient - builder.Services.AddBffHttpClient(settings => settings.LearningHubApiUrl); + builder.Services.AddBffHttpClient(settings => settings.LearningHubApiUrl); // Register your BFF using httpclient IUserApiHttpClient builder.Services.AddBffHttpClient(settings => settings.UserApiUrl); @@ -96,9 +92,11 @@ builder.Services.AddScoped(sp => levelSwitch); builder.Services.AddScoped(); - // qqqq will need back in post removing asp.net shared - //builder.Services.AddScoped(); // had to change provider not to use it previously trying again - //builder.Services.AddScoped(); + builder.Services.AddScoped(); + + // qqqq will go in a shared DI service collection extension + builder.Services.AddScoped(); + builder.Services.AddScoped(); await builder.Build().RunAsync(); } diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs index f7d20a451..f08a7c09c 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/GenericAPIHttpClient.cs @@ -1,11 +1,8 @@ -// qqqq using LearningHub.Nhs.Shared.Interfaces.Http; +using LearningHub.Nhs.Shared.Interfaces.Http; -using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared; - -//namespace LearningHub.Nhs.WebUI.BlazorClient.Services // qqqq weird suggestion need to shame namespace!!?? -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared +namespace LearningHub.Nhs.WebUI.BlazorClient.Services { - public class GenericAPIHttpClient : IAPIHttpClient, ILearningHubHttpClient, IUserApiHttpClient, IOpenApiHttpClient, ILearningHubHttpClientTest // Implementing multiple interfaces + public class GenericAPIHttpClient : IAPIHttpClient, ILearningHubHttpClient, IUserApiHttpClient, IOpenApiHttpClient { private readonly HttpClient _httpClient; // Private field to hold the injected HttpClient diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs index b8d5239ca..3640c206c 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Services/WasmCacheServiceStub.cs @@ -1,9 +1,10 @@ -using LearningHub.Nhs.Caching;// has aspnetcore in it qqqq we just need the interface +using LearningHub.Nhs.Caching; namespace LearningHub.Nhs.WebUI.BlazorClient.Services { /// /// We may use storage, we may just stub it and throw an error, we cant directly use redis we may access it via an api + /// The cachestub currently just returns there is nothing available so the caller then will revert to calling the api. /// public class WasmCacheServiceStub : ICacheService { diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor index bc90b9c40..39590e7eb 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor +++ b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/APITestDeleteME.razor @@ -1,17 +1,19 @@ -@using LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared @*remove later qqqq*@ - -@*@using Microsoft.AspNetCore.Components;qqqq*@ -@inject ILearningHubHttpClientTest LearningHubBFFHttpClient +@using LearningHub.Nhs.Shared.Interfaces.Http +@inject ILearningHubHttpClient LearningHubBFFHttpClient @inherits TELBlazor.Components.Core.TELComponentBase -@*we are hiding what is in the base class by doing the logger this way but the telbutton does it to so it needs sorting*@
+

⚠️ Works when required service packages moved to BlazorClient currently will fail on call, happens due to the runtime hack AllowUsingAspNetCoreInBlazorWasm ⚠️

+
+ Response from custom endpoint: +
@APIResponse
+
@code { string ApiRoute = "Catalogue/GetLatestCatalogueAccessRequest/43"; // Default route 500 - + string? APIResponse = "No response yet"; protected override void OnInitialized() @@ -31,8 +33,7 @@ private async Task CallApi() { try - { - + { Logger.LogInformation("Base Component"); var httpClient = await LearningHubBFFHttpClient.GetClientAsync(); @@ -44,57 +45,22 @@ Logger.LogInformation("Making request to: {FullUrl}", fullUrl); // Now use standard HttpClient methods - var response = await httpClient.GetAsync(ApiRoute); //qqqq here it doesnt seem to be using base address + var response = await httpClient.GetAsync(ApiRoute); string responseContent = await response.Content.ReadAsStringAsync(); Logger.LogInformation("API Response - Status: {Status}, Content: {Content}", response.StatusCode, responseContent); + + var content = await response.Content.ReadAsStringAsync(); + APIResponse = $"**Status:** {response.StatusCode}\n\n{content}"; /* qqqq - * // https://bff/lh-api.dev.local/api/Catalogue/GetLatestCatalogueAccessRequest/500 - wrong * // -> think need // https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500 - - - - - // "LearningHubApiUrl": "https://lh-api.dev.local/api/", - // "LearningHubApiBFFUrl": "https://bff/lh-api.dev.local/api/", - // IOptions webSettings, - // this.WebSettings.LearningHubApiUrl; - client.BaseAddress = new Uri(publicSettings.LearningHubApiBFFUrl); // or whatever your BFF port is - }); - */ - // Register your BFF-pointing clients - // var client = await HttpClient.GetClientAsync(); - // Console.WriteLine("ConsoleWriteline:APIClient BaseAddress: {Route}", client.BaseAddress); - // Logger.LogInformation("APIClient BaseAddress: {Route}", client.BaseAddress); - // var response = await client.GetAsync(ApiRoute); - // string responseContent = await response.Content.ReadAsStringAsync(); - // int statusCode = (int)response.StatusCode; - - // if (response.IsSuccessStatusCode) - // { - // Console.WriteLine("ConsoleWriteline: API call successful! Status: {StatusCode}, Content: {Content}", statusCode, responseContent); - // Logger.LogInformation("API call successful! Status: {StatusCode}, Content: {Content}", statusCode, responseContent); - // } - // else - // { - // Console.WriteLine("ConsoleWriteline: API call failed! Status: {StatusCode}, Error Content: {ErrorContent}", statusCode, responseContent); - // Logger.LogError("API call failed! Status: {StatusCode}, Error Content: {ErrorContent}", statusCode, responseContent); - // } - - - // await Task.Delay(1000); - // StateHasChanged(); - + */ } catch (Exception ex) { - // FIX 5: Log exceptions with ILogger. - Logger.LogCritical("in exception"); - Logger.LogCritical(ex,"argh"); Logger.LogError(ex, "An error occurred during API call to route: {Route}", ApiRoute); - } } } \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs deleted file mode 100644 index 8c19dd22f..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IAPIHttpClient.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Represents an HTTP client for a specific API. - /// - public interface IAPIHttpClient - { - /// - /// Gets the configured for the API. - /// - Task GetClientAsync(); - - /// - /// Gets the base URL of the API. - /// - string ApiUrl { get; } - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs deleted file mode 100644 index 4299dee7e..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IFindwiseSettingsPublic.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Represents configuration values related to Findwise search that are safe to expose - /// to client-side applications or public-facing APIs. - /// - /// - /// This includes non-sensitive values such as page sizes for different types of search results. - /// It does not contain any secure credentials or internal service configuration. - /// - /// - public interface IFindwiseSettingsPublic - { - /// - /// Gets or sets the page size for resource search results. - /// - public int ResourceSearchPageSize { get; set; } - - /// - /// Gets or sets the CatalogueSearchPageSize. - /// - public int CatalogueSearchPageSize { get; set; } - - /// - /// Gets or sets the AllCatalogueSearchPageSize. - /// - public int AllCatalogueSearchPageSize { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs deleted file mode 100644 index 529f26ccd..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClient.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Marker interface for the LearningHub API HttpClient. - /// - /// - /// Inherits from to enable - /// dependency injection of a specific implementation configured with - /// different API endpoints or settings specific to LH API. - /// - /// - /// - /// Currently, this interface is empty and used solely to differentiate implementations - /// that connect to different endpoints via configuration, but it may be extended in the future - /// with LearningHub-specific functionality or properties. - /// - /// - public interface ILearningHubHttpClient : IAPIHttpClient - { - - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs deleted file mode 100644 index 65e99c06b..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/ILearningHubHttpClientTest.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Marker interface for the LearningHub API HttpClient. - /// - /// - /// Inherits from to enable - /// dependency injection of a specific implementation configured with - /// different API endpoints or settings specific to LH API. - /// - /// - /// - /// Currently, this interface is empty and used solely to differentiate implementations - /// that connect to different endpoints via configuration, but it may be extended in the future - /// with LearningHub-specific functionality or properties. - /// - /// - public interface ILearningHubHttpClientTest : IAPIHttpClient - { - - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs deleted file mode 100644 index 6388090e4..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IOpenAPIHttpClient.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Marker interface for the IOpenAPIHttpClient API HttpClient. - /// - /// - /// Inherits from to enable - /// dependency injection of a specific implementation configured with - /// a openapi-related API endpoint or settings. - /// - /// - /// - /// This interface is currently empty and used solely to differentiate - /// implementations that connect to different endpoints via configuration. - /// It may be extended in the future with user-specific functionality or properties. - /// - /// - public interface IOpenApiHttpClient : IAPIHttpClient - { - - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs deleted file mode 100644 index b5fec3d17..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IPublicSettings.cs +++ /dev/null @@ -1,51 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Defines a contract for configuration data that is non-sensitive and safe to expose publicly - /// - /// - /// This interface exposes only data that is safe to be publicly consumed or shared, - /// such as API endpoint URLs or non-sensitive configuration values. - /// It explicitly excludes any private or sensitive information (e.g., authentication tokens, - /// credentials, or secret keys), which should be handled via separate interfaces or services. - /// - /// - /// - /// The data provided by this interface can be safely used in frontend technologies, - /// such as Blazor WebAssembly, JavaScript frameworks, or other client-side applications, - /// without risking exposure of sensitive information. - /// - /// - public interface IPublicSettings - { - /// - /// Gets or sets the LearningHubApiUrl. - /// - string LearningHubApiUrl { get; set; } - - /// - /// Gets or sets the UserApiUrl. - /// - string UserApiUrl { get; set; } - - /// - /// Gets or sets the LearningHubAdminUrl. - /// - string LearningHubAdminUrl { get; set; } - - /// - /// Gets or sets the OpenApiUrl. - /// - string OpenApiUrl { get; set; } - - /// - /// Gets or sets the LearningHubApiBFFUrl used to proxy via same domain cookie to the BFF LearningHubAPI calls. - /// - string LearningHubApiBFFUrl { get; set; } - - /// - /// Gets or sets the Findwise settings. - /// - IFindwiseSettingsPublic FindwiseSettings { get; set; } - } -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs deleted file mode 100644 index 1afee3f81..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/IUserAPIHttpClient.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Marker interface for the User API HttpClient. - /// - /// - /// Inherits from to enable - /// dependency injection of a specific implementation configured with - /// a user-related API endpoint or settings. - /// - /// - /// - /// This interface is currently empty and used solely to differentiate - /// implementations that connect to different endpoints via configuration. - /// It may be extended in the future with user-specific functionality or properties. - /// - /// - public interface IUserApiHttpClient : IAPIHttpClient - { - - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs deleted file mode 100644 index 68292192e..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/FromShared/PublicSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace LearningHub.Nhs.WebUI.BlazorClient.TestDeleteMe.FromShared -{ - /// - /// Represents configuration values that are safe to expose to clientside frontend applications - /// (such as Blazor WebAssembly) or public-facing APIs. - /// - /// - /// Implements and contains only non-sensitive, non-secret - /// values such as public API endpoints and pagination settings. This separation ensures - /// that secure or private configuration data is not inadvertently exposed to clients. - /// - /// - public class PublicSettings : IPublicSettings - { - /// - public string LearningHubApiUrl { get; set; } - /// - public string UserApiUrl { get; set; } - /// - public string LearningHubAdminUrl { get; set; } - /// - /// Gets or sets the OpenApiUrl. - /// - public string OpenApiUrl { get; set; } - /// - /// Backend for Frontend (BFF) URL for the Learning Hub API accessed by samesite cookie and uses httpclients with bearers to access external apis. - /// - public string LearningHubApiBFFUrl { get; set; } - /// - public IFindwiseSettingsPublic FindwiseSettings { get; set; } - - } -} diff --git a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor b/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor deleted file mode 100644 index 6550626dd..000000000 --- a/LearningHub.Nhs.WebUI.BlazorClient/TestDeleteMe/HelloWorld.razor +++ /dev/null @@ -1,25 +0,0 @@ -@inherits TELBlazor.Components.Core.TELComponentBase -@inject ILogger Logger -

Hello Blazor!

-

If you see this and the console message, Blazor WASM code is running.

- -

Button has been clicked: @clickCount times.

- - -@code { - private int clickCount = 0; // Initialize a counter - protected override void OnInitialized() - { - base.OnInitialized(); // Call the base method - Console.WriteLine("-----> SimpleTest Component Initialized! If you see this, Blazor WASM code is executing."); - } - - private void HandleButtonClick() - { - // This C# code will run when the button is clicked. - Console.WriteLine("----> Button was clicked! C# method executed."); - - clickCount++; - Logger.LogWarning("serilog in simple"); - } -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor index c7837620c..1289a8aff 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor +++ b/LearningHub.Nhs.WebUI.BlazorClient/_Imports.razor @@ -1,9 +1,4 @@ @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using static Microsoft.AspNetCore.Components.Web.RenderMode -@using LearningHub.Nhs.WebUI.BlazorClient - -@*qqqq may not be needed try dropping and see logging still works*@ -@using Microsoft.AspNetCore.Components; -@using Microsoft.Extensions.Logging; -@using TELBlazor.Components.Core.Configuration; \ No newline at end of file +@using LearningHub.Nhs.WebUI.BlazorClient \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs index da3f79fd4..ef3cf02de 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/BFFController.cs @@ -23,7 +23,7 @@ /// See confluence for more details on the BFF pattern and how to use this controller. ///
/// The authorize same site cookie is used for security between client and server. API calls relying on policys such as AuthorizeOrCallFromLH may not be proxied as they require the Authorization header to be present. - [Authorize] // QQQQ !!!! PUTBACKIN !!!!!!!!!!!!!!!!!! + [Authorize] [Route("bff/{apiName}/{**path}")] [ApiController] public class BFFController : BaseApiController @@ -78,8 +78,7 @@ public async Task ProxyRequest(string apiName, string path) string sanitizedPath = path?.Trim('/').ToLowerInvariant() ?? string.Empty; string sanitizedApiName = apiName?.Trim('/').ToLowerInvariant() ?? string.Empty; - // https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500 - // qqqq lh-api.dev.local getting this + // qqqq https://lh-web.dev.local/bff/lh-api.dev.local/Catalogue/GetLatestCatalogueAccessRequest/500 IAPIHttpClient apiClient; try { @@ -242,7 +241,6 @@ private bool IsPathAllowed(string path) } // Check whitelist - // qqqqq catalogue/ vs "catalogue/getlatestcatalogueaccessrequest/500" return this.bffPathValidationOptions.Value.AllowedPathPrefixes.Any(prefix => normalizedPath.StartsWith(prefix.ToLowerInvariant())); } } diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj index 01ab821eb..0d3ee42db 100644 --- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj +++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj @@ -110,9 +110,6 @@ - - - @@ -122,7 +119,7 @@ - + diff --git a/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs b/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs index de4613295..9af95a1e6 100644 --- a/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs +++ b/LearningHub.Nhs.WebUI/Services/LearningHubHttpClient.cs @@ -12,7 +12,7 @@ /// /// The learning hub http client. /// - public class LearningHubHttpClient : BaseHttpClient, ILearningHubHttpClient // qqqq + public class LearningHubHttpClient : BaseHttpClient, ILearningHubHttpClient { /// /// Initializes a new instance of the class. diff --git a/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs b/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs index 9772556f3..bae626eb1 100644 --- a/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs +++ b/LearningHub.Nhs.WebUI/Services/NLogLogLevelSwitcherService.cs @@ -9,8 +9,6 @@ using TELBlazor.Components.Core.Models.Logging; using TELBlazor.Components.Core.Services.HelperServices; - // qqqq this file needs completely reviewing - /// /// Provides functionality for managing log levels in applications using NLog. /// @@ -61,16 +59,6 @@ public string GetCurrentLogLevel() /// public string SetLogLevel(string level) { - // if (string.IsNullOrWhiteSpace(level)) - // { - // _logger.LogWarning("Log level was null or empty."); - // return GetCurrentLogLevel(); - // } - // if (!Enum.TryParse(level, true, out var parsedLevel)) - // { - // _logger.LogWarning("Invalid log level: {Level}", level); - // return GetCurrentLogLevel(); - // } this.logger.LogInformation("Requested to change log level to {Level}, but NLog does not support runtime changes in WASM.", level); this.LogAllLevels("After 'Change'"); @@ -105,23 +93,5 @@ private async Task StoreLogLevelWithTimestamp(string level) this.logger.LogError(ex, "Error storing log level to local storage."); } } - - // private async Task GetStoredLogLevelWithExpiration() - // { - // try - // { - // var storedItem = await _localStorage.GetItemAsync(LogLevelKey); - // if (storedItem == null || DateTime.UtcNow > storedItem.Expires) - // { - // await _localStorage.RemoveItemAsync(LogLevelKey); - // return null; - // } - // return storedItem.Level; - // } - // catch - // { - // return null; - // } - // } } } diff --git a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs index 300b39c02..4d7351916 100644 --- a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs +++ b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs @@ -48,15 +48,6 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }); - // qqqq remove test - services.AddHttpClient() - .ConfigurePrimaryHttpMessageHandler( - () => new HttpClientHandler - { - ServerCertificateCustomValidationCallback = - HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, - }); - services.AddHttpClient() .ConfigurePrimaryHttpMessageHandler( () => new HttpClientHandler diff --git a/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml b/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml index 4ca7e15b3..0fa63d1aa 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/LandingPage.cshtml @@ -38,8 +38,6 @@ -

My accessed learning

-
- public class FindwiseSettingsPublic : IFindwiseSettingsPublic + public class ExposableFindwiseSettings : IExposableFindwiseSettings { /// /// Gets or sets the ResourceSearchPageSize. diff --git a/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs b/LearningHub.Nhs.Shared/Configuration/ExposableSettings.cs similarity index 84% rename from LearningHub.Nhs.Shared/Configuration/PublicSettings.cs rename to LearningHub.Nhs.Shared/Configuration/ExposableSettings.cs index 0250a4c08..25a82505b 100644 --- a/LearningHub.Nhs.Shared/Configuration/PublicSettings.cs +++ b/LearningHub.Nhs.Shared/Configuration/ExposableSettings.cs @@ -6,12 +6,12 @@ /// (such as Blazor WebAssembly) or public-facing APIs. /// /// - /// Implements and contains only non-sensitive, non-secret + /// Implements and contains only non-sensitive, non-secret /// values such as public API endpoints and pagination settings. This separation ensures /// that secure or private configuration data is not inadvertently exposed to clients. /// /// - public class PublicSettings : IPublicSettings + public class ExposableSettings : IExposableSettings { /// public string LearningHubApiUrl { get; set; } @@ -30,7 +30,7 @@ public class PublicSettings : IPublicSettings /// public string LearningHubApiBFFUrl { get; set; } /// - public IFindwiseSettingsPublic FindwiseSettings { get; set; } + public IExposableFindwiseSettings FindwiseSettings { get; set; } } } diff --git a/LearningHub.Nhs.Shared/Interfaces/Configuration/IFindwiseSettingsPublic.cs b/LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableFindwiseSettings.cs similarity index 95% rename from LearningHub.Nhs.Shared/Interfaces/Configuration/IFindwiseSettingsPublic.cs rename to LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableFindwiseSettings.cs index e63a98039..3c3a9691a 100644 --- a/LearningHub.Nhs.Shared/Interfaces/Configuration/IFindwiseSettingsPublic.cs +++ b/LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableFindwiseSettings.cs @@ -9,7 +9,7 @@ /// It does not contain any secure credentials or internal service configuration. /// /// - public interface IFindwiseSettingsPublic + public interface IExposableFindwiseSettings { /// /// Gets or sets the page size for resource search results. diff --git a/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs b/LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableSettings.cs similarity index 93% rename from LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs rename to LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableSettings.cs index d47db86c0..753858fba 100644 --- a/LearningHub.Nhs.Shared/Interfaces/Configuration/IPublicSettings.cs +++ b/LearningHub.Nhs.Shared/Interfaces/Configuration/IExposableSettings.cs @@ -16,7 +16,7 @@ /// without risking exposure of sensitive information. /// /// - public interface IPublicSettings + public interface IExposableSettings { /// /// Gets or sets the LearningHubApiUrl. @@ -37,6 +37,6 @@ public interface IPublicSettings /// public string LearningHubApiBFFUrl { get; set; } - public IFindwiseSettingsPublic FindwiseSettings { get; set; } + public IExposableFindwiseSettings FindwiseSettings { get; set; } } } diff --git a/LearningHub.Nhs.Shared/Services/SearchService.cs b/LearningHub.Nhs.Shared/Services/SearchService.cs index d98d6b34f..ab6dc87fb 100644 --- a/LearningHub.Nhs.Shared/Services/SearchService.cs +++ b/LearningHub.Nhs.Shared/Services/SearchService.cs @@ -29,7 +29,7 @@ /// public class SearchService : BaseService, ISearchService { - private readonly IPublicSettings publicSettings; + private readonly IExposableSettings ExposableSettings; private IProviderService providerService; /// @@ -38,15 +38,15 @@ public class SearchService : BaseService, ISearchService /// The Open Api Http Client. /// Provider service. /// Logger. - /// Settings. + /// Settings. public SearchService( IOpenApiHttpClient openApiHttpClient, IProviderService providerService, ILogger logger, - IOptions publicSettings) + IOptions ExposableSettings) : base(openApiHttpClient, logger) { - this.publicSettings = publicSettings.Value; + this.ExposableSettings = ExposableSettings.Value; this.providerService = providerService; } @@ -73,8 +73,8 @@ public async Task PerformSearch(IPrincipal user, SearchRe var suggestedCatalogue = string.Empty; var suggestedResource = string.Empty; - var resourceSearchPageSize = this.publicSettings.FindwiseSettings.ResourceSearchPageSize; - var catalogueSearchPageSize = this.publicSettings.FindwiseSettings.CatalogueSearchPageSize; + var resourceSearchPageSize = this.ExposableSettings.FindwiseSettings.ResourceSearchPageSize; + var catalogueSearchPageSize = this.ExposableSettings.FindwiseSettings.CatalogueSearchPageSize; var resourceSearchRequestModel = new SearchRequestModel { @@ -259,8 +259,8 @@ public async Task PerformSearch(IPrincipal user, SearchRe public async Task RegisterSearchEventsAsync(SearchRequestViewModel search, SearchFormActionTypeEnum action, int resourceCount = 0, int catalogueCount = 0) { var eventId = 0; - var resourceSearchPageSize = this.publicSettings.FindwiseSettings.ResourceSearchPageSize; - var catalogueSearchPageSize = this.publicSettings.FindwiseSettings.CatalogueSearchPageSize; + var resourceSearchPageSize = this.ExposableSettings.FindwiseSettings.ResourceSearchPageSize; + var catalogueSearchPageSize = this.ExposableSettings.FindwiseSettings.CatalogueSearchPageSize; var sortBy = search.Sortby.HasValue ? (SearchSortTypeEnum)search.Sortby : SearchSortTypeEnum.Relevance; @@ -517,7 +517,7 @@ public async Task SubmitFeedbackAsync(SearchFeedBackModel model) int createId = 0; var client = await this.OpenApiHttpClient.GetClientAsync(); - var request = this.publicSettings.LearningHubApiUrl + "Search/SubmitFeedback"; + var request = this.ExposableSettings.LearningHubApiUrl + "Search/SubmitFeedback"; var content = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json"); var response = await client.PostAsync(request, content).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs b/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs index 373445cf1..3be1a1cb2 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/DI/DI.cs @@ -11,19 +11,19 @@ namespace LearningHub.Nhs.WebUI.BlazorClient.DI { public static class DI { - public static IHttpClientBuilder AddBffHttpClient(this IServiceCollection services, Func getApiUrl) + public static IHttpClientBuilder AddBffHttpClient(this IServiceCollection services, Func getApiUrl) where TInterface : class where TImplementation : class, TInterface { return services.AddHttpClient((serviceProvider, client) => { - var publicSettings = serviceProvider.GetRequiredService>().Value; - var apiUrl = getApiUrl(publicSettings); + var ExposableSettings = serviceProvider.GetRequiredService>().Value; + var apiUrl = getApiUrl(ExposableSettings); var apiUri = new Uri(apiUrl); var apiHost = apiUri.Host; string forwardSlash = "/"; // Using the Uri class for robust path joining - client.BaseAddress = new Uri($"{publicSettings.LearningHubApiBFFUrl}{apiHost}{forwardSlash}"); + client.BaseAddress = new Uri($"{ExposableSettings.LearningHubApiBFFUrl}{apiHost}{forwardSlash}"); }); } } diff --git a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs index 9b494c66a..d93936295 100644 --- a/LearningHub.Nhs.WebUI.BlazorClient/Program.cs +++ b/LearningHub.Nhs.WebUI.BlazorClient/Program.cs @@ -42,7 +42,7 @@ builder.Configuration.AddJsonStream(envSettings); -builder.Services.Configure(builder.Configuration.GetSection("Settings")); +builder.Services.Configure(builder.Configuration.GetSection("Settings")); builder.Logging.ClearProviders(); // Read default logging level from configuration diff --git a/LearningHub.Nhs.WebUI/Configuration/Settings.cs b/LearningHub.Nhs.WebUI/Configuration/Settings.cs index b20d175b1..b8a26f73b 100644 --- a/LearningHub.Nhs.WebUI/Configuration/Settings.cs +++ b/LearningHub.Nhs.WebUI/Configuration/Settings.cs @@ -8,7 +8,7 @@ namespace LearningHub.Nhs.WebUI.Configuration /// /// Defines the . /// - public class Settings : IPublicSettings + public class Settings : IExposableSettings { /// /// Initializes a new instance of the class. @@ -259,7 +259,7 @@ public Settings() /// /// Gets or sets the FindwiseSettings. /// - public IFindwiseSettingsPublic FindwiseSettings { get; set; } = new FindwiseSettingsPublic(); + public IExposableFindwiseSettings FindwiseSettings { get; set; } = new ExposableFindwiseSettings(); /// /// Gets or sets the MediaKindSettings.