diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml index f1609bb44..94fca85b0 100644 --- a/.github/workflows/continuous-integration-workflow.yml +++ b/.github/workflows/continuous-integration-workflow.yml @@ -9,99 +9,38 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v3 - - - name: Modify web.config files in all apps - shell: pwsh - run: | - $webConfigPaths = @( - "${{ github.workspace }}\AdminUI\LearningHub.Nhs.AdminUI\web.config", - "${{ github.workspace }}\WebAPI\LearningHub.Nhs.Api\web.config", - "${{ github.workspace }}\LearningHub.Nhs.WebUI\web.config" - ) - - foreach ($path in $webConfigPaths) { - if (Test-Path $path) { - Write-Host "Modifying $path" - [xml]$config = Get-Content $path - - if (-not $config.configuration.'system.webServer') { - $systemWebServer = $config.CreateElement("system.webServer") - $config.configuration.AppendChild($systemWebServer) | Out-Null - } else { - $systemWebServer = $config.configuration.'system.webServer' - } - - if (-not $systemWebServer.httpProtocol) { - $httpProtocol = $config.CreateElement("httpProtocol") - $systemWebServer.AppendChild($httpProtocol) | Out-Null - } else { - $httpProtocol = $systemWebServer.httpProtocol - } - - if (-not $httpProtocol.customHeaders) { - $customHeaders = $config.CreateElement("customHeaders") - $httpProtocol.AppendChild($customHeaders) | Out-Null - } else { - $customHeaders = $httpProtocol.customHeaders - } - - foreach ($name in @("X-Powered-By", "Server")) { - $removeNode = $config.CreateElement("remove") - $removeNode.SetAttribute("name", $name) - $customHeaders.AppendChild($removeNode) | Out-Null - } - - if (-not $systemWebServer.security) { - $security = $config.CreateElement("security") - $systemWebServer.AppendChild($security) | Out-Null - } else { - $security = $systemWebServer.security - } - - if (-not $security.requestFiltering) { - $requestFiltering = $config.CreateElement("requestFiltering") - $requestFiltering.SetAttribute("removeServerHeader", "true") - $security.AppendChild($requestFiltering) | Out-Null - } - - $config.Save($path) - } else { - Write-Host "File not found: $path" - } - } - + - name: Setup .NET Core SDK 8.0 uses: actions/setup-dotnet@v3 with: dotnet-version: 8.0.x - name: Add Azure artifact - run: dotnet nuget add source 'https://pkgs.dev.azure.com/e-LfH/_packaging/LearningHubFeed/nuget/v3/index.json' --name 'LearningHubFeed' --username 'kevin.whittaker' --password ${{ secrets.AZURE_DEVOPS_PAT }} --store-password-in-clear-text + run: | + dotnet nuget remove source LearningHubFeed || true + dotnet nuget add source 'https://pkgs.dev.azure.com/e-LfH/_packaging/LearningHubFeed/nuget/v3/index.json' --name 'LearningHubFeed' --username 'kevin.whittaker' --password ${{ secrets.AZURE_DEVOPS_PAT }} --store-password-in-clear-text - - name: Use Node 20 with Yarn + - name: Use Node 14 uses: actions/setup-node@v4 with: - node-version: '20' - cache: 'npm' - - - name: Upgrade npm to the latest version - run: npm install -g npm@6.14.8 + node-version: '14' + cache: 'npm' - - name: Typescript install WebUI - run: yarn install --network-timeout 600000 --frozen-lockfile + - name: npm install WebUI + run: npm install working-directory: ./LearningHub.Nhs.WebUI - - - name: Typescript build WebUI - run: yarn build:webpack + + - name: npm build WebUI + run: npm run build:webpack working-directory: ./LearningHub.Nhs.WebUI - - name: Typescript install AdminUI - run: yarn install + - name: npm install AdminUI + run: npm install working-directory: ./AdminUI/LearningHub.Nhs.AdminUI - - - name: Typescript build AdminUI - run: yarn build:webpack - working-directory: ./AdminUI/LearningHub.Nhs.AdminUI + + - name: npm build AdminUI + run: npm run build:webpack + working-directory: ./AdminUI/LearningHub.Nhs.AdminUI - name: Setup MSBuild uses: microsoft/setup-msbuild@v1.0.3 @@ -181,5 +120,4 @@ jobs: } # - name: Test - # run: dotnet test ${{ env.BuildParameters.TestProjects }} - + # run: dotnet test ${{ env.BuildParameters.TestProjects }} diff --git a/.gitignore b/.gitignore index fcd06e014..8cc7d8bbe 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,6 @@ obj /AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj.user /WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj.user /ReportAPI/LearningHub.Nhs.ReportApi/web.config +/AdminUI/LearningHub.Nhs.AdminUI/web.config +/LearningHub.Nhs.WebUI/web.config +/WebAPI/LearningHub.Nhs.API/web.config diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Configuration/WebSettings.cs b/AdminUI/LearningHub.Nhs.AdminUI/Configuration/WebSettings.cs index f8e3c1565..5c8ab554f 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Configuration/WebSettings.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Configuration/WebSettings.cs @@ -27,6 +27,11 @@ public class WebSettings /// public string LearningHubApiUrl { get; set; } + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// /// Gets or sets the user api url. /// diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Controllers/UserGroupController.cs b/AdminUI/LearningHub.Nhs.AdminUI/Controllers/UserGroupController.cs index 1be7f211c..05364adaf 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Controllers/UserGroupController.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Controllers/UserGroupController.cs @@ -197,7 +197,15 @@ public async Task Details(UserGroupAdminDetailViewModel userGroup if (userGroup.IsNew()) { validationResult = await this.userGroupService.CreateUserGroup(userGroup); - userGroup = await this.userGroupService.GetUserGroupAdminDetailbyIdAsync(validationResult.CreatedId.Value); + if (validationResult.IsValid) + { + userGroup = await this.userGroupService.GetUserGroupAdminDetailbyIdAsync(validationResult.CreatedId.Value); + } + else + { + this.ViewBag.ErrorMessage = $"Update failed: {string.Join(Environment.NewLine, validationResult.Details)}"; + return this.View("Details", userGroup); + } } else { diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Controllers/api/UserController.cs b/AdminUI/LearningHub.Nhs.AdminUI/Controllers/api/UserController.cs deleted file mode 100644 index d2b97e13c..000000000 --- a/AdminUI/LearningHub.Nhs.AdminUI/Controllers/api/UserController.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace LearningHub.Nhs.AdminUI.Controllers.Api -{ - using System; - using System.Collections.Generic; - using System.Threading.Tasks; - using elfhHub.Nhs.Models.Common; - using elfhHub.Nhs.Models.Enums; - using LearningHub.Nhs.AdminUI.Interfaces; - using Microsoft.AspNetCore.Authorization; - using Microsoft.AspNetCore.Mvc; - using Microsoft.Extensions.Logging; - using Microsoft.Extensions.Options; - - /// - /// The UserController class. - /// - [Authorize] - [Route("api/[controller]")] - [ApiController] - public class UserController : BaseApiController - { - /// - /// The elfh user service.. - /// - private IUserService userService; - - /// - /// Initializes a new instance of the class. - /// - /// The userService. - /// loginWizardService. - /// logger. - /// Settings. - public UserController(IUserService userService, ILogger logger) - : base(logger) - { - this.userService = userService; - } - - /// - /// The SessionTimeout. - /// - /// The . - [HttpPost("browser-close")] - public IActionResult BrowserClose() - { - // Add browser close to the UserHistory - UserHistoryViewModel userHistory = new UserHistoryViewModel() - { - UserId = this.CurrentUserId, - UserHistoryTypeId = (int)UserHistoryType.Logout, - Detail = @"User browser closed", - }; - - this.userService.StoreUserHistory(userHistory); - - return this.Ok(true); - } - } -} diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Helpers/IOpenApiFacade.cs b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/IOpenApiFacade.cs new file mode 100644 index 000000000..2bcded72b --- /dev/null +++ b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/IOpenApiFacade.cs @@ -0,0 +1,59 @@ +namespace LearningHub.Nhs.AdminUI.Helpers +{ + using System.Threading.Tasks; + using LearningHub.Nhs.Models.Common; + + /// + /// Defines the . + /// + public interface IOpenApiFacade + { + /// + /// The GetAsync. + /// + /// The type. + /// The url. + /// The . + Task GetAsync(string url) + where T : class, new(); + + /// + /// The PostAsync. + /// + /// The type. + /// The url. + /// The body. + /// The . + Task PostAsync(string url, T body) + where T : class, new(); + + /// + /// The PostAsync. + /// + /// The type. + /// . + /// The url. + /// The body. + /// The . + Task PostAsync(string url, TBody body) + where T : class, new() + where TBody : class, new(); + + /// + /// The PutAsync. + /// + /// The url. + /// The . + Task PutAsync(string url); + + /// + /// The PutAsync. + /// + /// . + /// The url. + /// The body. + /// The . + Task PutAsync(string url, T body) + where T : class, new(); + } +} diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Helpers/LearningActivityHelper.cs b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/LearningActivityHelper.cs index caffaaa5d..b67989350 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Helpers/LearningActivityHelper.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/LearningActivityHelper.cs @@ -85,7 +85,15 @@ public static string GetResourceTypeVerb(this MyLearningDetailedItemViewModel my case ResourceTypeEnum.Article: return "Read"; case ResourceTypeEnum.Audio: - return "Played " + GetDurationText(myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000); + if ((myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000) > myLearningDetailedItemViewModel.ResourceDurationMilliseconds) + { + return "Played " + GetDurationText(myLearningDetailedItemViewModel.ResourceDurationMilliseconds); + } + else + { + return "Played " + GetDurationText(myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000); + } + case ResourceTypeEnum.Embedded: return string.Empty; case ResourceTypeEnum.Equipment: @@ -113,7 +121,15 @@ public static string GetResourceTypeVerb(this MyLearningDetailedItemViewModel my } case ResourceTypeEnum.Video: - return "Played " + GetDurationText(myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000); + if ((myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000) > myLearningDetailedItemViewModel.ResourceDurationMilliseconds) + { + return "Played " + GetDurationText(myLearningDetailedItemViewModel.ResourceDurationMilliseconds); + } + else + { + return "Played " + GetDurationText(myLearningDetailedItemViewModel.ActivityDurationSeconds * 1000); + } + case ResourceTypeEnum.WebLink: return "Visited"; case ResourceTypeEnum.Html: diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Helpers/OpenApiFacade.cs b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/OpenApiFacade.cs new file mode 100644 index 000000000..6169d8e6b --- /dev/null +++ b/AdminUI/LearningHub.Nhs.AdminUI/Helpers/OpenApiFacade.cs @@ -0,0 +1,241 @@ +namespace LearningHub.Nhs.AdminUI.Helpers +{ + using System; + using System.Net.Http; + using System.Text; + using System.Threading.Tasks; + using LearningHub.Nhs.AdminUI.Interfaces; + using LearningHub.Nhs.Models.Common; + using Newtonsoft.Json; + + /// + /// Defines the . + /// + public class OpenApiFacade : IOpenApiFacade + { + /// + /// Defines the _client. + /// + private readonly IOpenApiHttpClient client; + + /// + /// Initializes a new instance of the class. + /// + /// The client. + public OpenApiFacade(IOpenApiHttpClient client) + { + this.client = client; + } + + /// + /// The GetAsync. + /// + /// . + /// The url. + /// The . + public async Task GetAsync(string url) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var vm = new T(); + + var response = await client.GetAsync(url).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + vm = JsonConvert.DeserializeObject(result); + + return vm; + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PostAsync. + /// + /// . + /// The url. + /// The body. + /// The . + public async Task PostAsync(string url, T body) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PostAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + return; + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PostAsync. + /// + /// The return type. + /// The type of body parameter. + /// The url. + /// The body. + /// The . + public async Task PostAsync(string url, TBody body) + where TBody : class, new() + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var vm = new T(); + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PostAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PostAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PutAsync. + /// + /// The url. + /// The . + public async Task PutAsync(string url) + { + var client = await this.client.GetClientAsync(); + + var response = await client.PutAsync(url, null).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PutAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PutAsync. + /// + /// . + /// The url. + /// The body. + /// The . + public async Task PutAsync(string url, T body) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PutAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PutAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + } +} diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Interfaces/IOpenApiHttpClient.cs b/AdminUI/LearningHub.Nhs.AdminUI/Interfaces/IOpenApiHttpClient.cs new file mode 100644 index 000000000..34c488767 --- /dev/null +++ b/AdminUI/LearningHub.Nhs.AdminUI/Interfaces/IOpenApiHttpClient.cs @@ -0,0 +1,17 @@ +namespace LearningHub.Nhs.AdminUI.Interfaces +{ + using System.Net.Http; + using System.Threading.Tasks; + + /// + /// The OpenApiHttpClient interface. + /// + public interface IOpenApiHttpClient + { + /// + /// The get client. + /// + /// The . + Task GetClientAsync(); + } +} diff --git a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj index eba6b6ffa..a0de54f8f 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj +++ b/AdminUI/LearningHub.Nhs.AdminUI/LearningHub.Nhs.AdminUI.csproj @@ -1,16 +1,16 @@ - + - - net8.0 - 1.0.0.0 - 1.0.0.0 - 1.0.0 - 31abd8b9-4223-4ff3-896b-a46530c9e15c - /subscriptions/57c55d5f-78c1-4373-a021-ff8357548f51/resourceGroups/LearningHubNhsUk-AdminUI-Prod-RG/providers/microsoft.insights/components/LearningHubNhsUk-AdminUI-Prod - true - true - x64 - + + net8.0 + 1.0.0.0 + 1.0.0.0 + 1.0.0 + 31abd8b9-4223-4ff3-896b-a46530c9e15c + /subscriptions/57c55d5f-78c1-4373-a021-ff8357548f51/resourceGroups/LearningHubNhsUk-AdminUI-Prod-RG/providers/microsoft.insights/components/LearningHubNhsUk-AdminUI-Prod + true + true + x64 + diff --git a/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs b/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs index 81867365f..1039a3673 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/ServiceCollectionExtension.cs @@ -86,6 +86,7 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur services.AddSingleton(configuration); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); @@ -132,11 +133,19 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }); + services.AddHttpClient() + .ConfigurePrimaryHttpMessageHandler( + () => new HttpClientHandler + { + ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, + }); } else { services.AddHttpClient(); services.AddHttpClient(); + services.AddHttpClient(); } services.AddTransient(); diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/BaseService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/BaseService.cs index ab2a377e8..c164b5691 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/BaseService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/BaseService.cs @@ -12,6 +12,11 @@ public class BaseService /// private ILearningHubHttpClient learningHubHttpClient; + /// + /// Defines the openApiHttpClient. + /// + private IOpenApiHttpClient openApiHttpClient; + /// /// Initializes a new instance of the class. /// @@ -21,9 +26,25 @@ protected BaseService(ILearningHubHttpClient learningHubHttpClient) this.learningHubHttpClient = learningHubHttpClient; } + /// + /// Initializes a new instance of the class. + /// + /// The learningHubHttpClient. + /// The openApiHttpClient. + protected BaseService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient) + { + this.learningHubHttpClient = learningHubHttpClient; + this.openApiHttpClient = openApiHttpClient; + } + /// /// Gets the LearningHubHttpClient. /// protected ILearningHubHttpClient LearningHubHttpClient => this.learningHubHttpClient; + + /// + /// Gets the OpenApiHttpClient. + /// + protected IOpenApiHttpClient OpenApiHttpClient => this.openApiHttpClient; } } diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/CatalogueService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/CatalogueService.cs index 1fa44df2b..2ac0088d9 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/CatalogueService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/CatalogueService.cs @@ -19,19 +19,21 @@ public class CatalogueService : BaseService, ICatalogueService /// /// Defines the _facade. /// - private readonly ILearningHubApiFacade facade; + private readonly IOpenApiFacade facade; /// /// Initializes a new instance of the class. /// /// The learningHubHttpClient. - /// The learningHubApiFacade. + /// The Open Api Http Client. + /// The openApiFacade. public CatalogueService( ILearningHubHttpClient learningHubHttpClient, - ILearningHubApiFacade learningHubApiFacade) + IOpenApiHttpClient openApiHttpClient, + IOpenApiFacade openApiFacade) : base(learningHubHttpClient) { - this.facade = learningHubApiFacade; + this.facade = openApiFacade; } /// diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/ContentService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/ContentService.cs index d49cd8422..ec983fffd 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/ContentService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/ContentService.cs @@ -27,15 +27,17 @@ public class ContentService : BaseService, IContentService /// private readonly IFileService fileService; private readonly IAzureMediaService azureMediaService; + private readonly IOpenApiHttpClient openApiHttpClient; /// /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The openApiHttpClient. /// The fileService. /// azureMediaService. - public ContentService(ILearningHubHttpClient learningHubHttpClient, IFileService fileService, IAzureMediaService azureMediaService) - : base(learningHubHttpClient) + public ContentService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IFileService fileService, IAzureMediaService azureMediaService) + : base(learningHubHttpClient, openApiHttpClient) { this.fileService = fileService; this.azureMediaService = azureMediaService; @@ -48,7 +50,7 @@ public ContentService(ILearningHubHttpClient learningHubHttpClient, IFileService /// The . public async Task DiscardAsync(int pageId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/discard/{pageId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -68,7 +70,7 @@ public async Task GetPageByIdAsync(int id, bool includeHidden = f { PageViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = !includeHidden ? $"content/page/{id}" : $"content/page-all/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -97,7 +99,7 @@ public async Task GetPageSectionDetailByIdAsync(int { PageSectionDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/page-section-detail/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -126,7 +128,7 @@ public async Task GetEditablePageSectionDetailByIdAs { PageSectionDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/editable-page-section-detail/{pageSectionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -154,7 +156,7 @@ public async Task GetPagesAsync() { PageResultViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/pages"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -181,7 +183,7 @@ public async Task GetPagesAsync() /// The . public async Task PublishAsync(int pageId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/publish/{pageId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -214,7 +216,7 @@ public async Task UpdatePageImageSectionDetailAsync(int pageId, PageImageSection var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/page-image-section-detail/{pageId}"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -232,7 +234,7 @@ public async Task UpdatePageImageSectionDetailAsync(int pageId, PageImageSection /// The . public async Task ChangeOrderAsync(UpdatePageSectionOrderModel requestViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "content/change-order/"; var content = new StringContent( JsonConvert.SerializeObject(requestViewModel), @@ -259,7 +261,7 @@ public async Task ChangeOrderAsync(UpdatePageSectionOrderModel requestViewModel) /// The . public async Task CloneAsync(int pageSectionId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/clone/{pageSectionId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -276,7 +278,7 @@ public async Task CloneAsync(int pageSectionId) /// The . public async Task HideAsync(int pageSectionId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/hide/{pageSectionId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -293,7 +295,7 @@ public async Task HideAsync(int pageSectionId) /// The . public async Task UnHideAsync(int pageSectionId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/unhide/{pageSectionId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -310,7 +312,7 @@ public async Task UnHideAsync(int pageSectionId) /// The . public async Task DeleteAsync(int pageSectionId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/delete/{pageSectionId}"; var response = await client.PutAsync(request, null).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || @@ -376,7 +378,7 @@ public async Task> GetFileTypeAsync() { List fileTypeList = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetFileTypes"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -459,7 +461,7 @@ public async Task SaveAttributeFileDetailsAsync(FileCreateRequestViewModel var json = JsonConvert.SerializeObject(fileCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/save-attribute-file"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -493,7 +495,7 @@ public async Task SaveVideoAssetAsync(FileCreateRequestViewModel fileCreate var json = JsonConvert.SerializeObject(fileCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/save-video-asset"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -593,7 +595,7 @@ public async Task GetFileChunkDetail(int fileChunkDeta { FileChunkDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetFileChunkDetail/{fileChunkDetailId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -624,7 +626,7 @@ public async Task SaveFileChunkDetailsAsync(FileChunkDetailViewModel fileCh var json = JsonConvert.SerializeObject(fileChunkDetailCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SaveFileChunkDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -682,7 +684,7 @@ public async Task RegisterChunkedFileAsync(FileChunkRegisterMo public async Task DeleteFileChunkDetailAsync(int fileChunkDetailId) { ApiResponse apiResponse = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteFileChunkDetail/{fileChunkDetailId}"; var response = await client.DeleteAsync(request).ConfigureAwait(false); @@ -814,7 +816,7 @@ public async Task UpdateVideoAssetAsync(VideoAssetViewModel model) var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/update-video-asset"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -844,7 +846,7 @@ public async Task UpdateVideoAssetAsync(VideoAssetViewModel model) /// The . public async Task CreatePageSectionAsync(PageSectionViewModel requestViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "content/create-page-section/"; var content = new StringContent( JsonConvert.SerializeObject(requestViewModel), @@ -874,7 +876,7 @@ public async Task CreatePageSectionAsync(PageSectionViewModel requestViewMo /// The . public async Task UpdatePageSectionDetailAsync(PageSectionDetailViewModel updateViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "content/update-page-section-detail/"; var content = new StringContent( JsonConvert.SerializeObject(updateViewModel), @@ -899,7 +901,7 @@ public async Task GetPageSectionDetailVideoAssetById { PageSectionDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"content/page-section-detail-video/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/EventService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/EventService.cs index 000fce940..db61e47e3 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/EventService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/EventService.cs @@ -18,8 +18,9 @@ public class EventService : BaseService, IEventService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. - public EventService(ILearningHubHttpClient learningHubHttpClient) - : base(learningHubHttpClient) + /// The openApiHttpClient. + public EventService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient) + : base(learningHubHttpClient, openApiHttpClient) { } @@ -30,7 +31,7 @@ public async Task Create(Event eventEntity) var json = JsonConvert.SerializeObject(eventEntity); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Event/Create"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/HierarchyService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/HierarchyService.cs index b408cb637..17b37999b 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/HierarchyService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/HierarchyService.cs @@ -16,21 +16,21 @@ public class HierarchyService : BaseService, IHierarchyService /// /// Defines the _facade. /// - private readonly ILearningHubApiFacade facade; + private readonly IOpenApiFacade facade; /// /// Initializes a new instance of the class. /// /// The learning hub http client. - /// The learningHubApiFacade. + /// The openApiFacade. /// The logger. public HierarchyService( ILearningHubHttpClient learningHubHttpClient, - ILearningHubApiFacade learningHubApiFacade, + IOpenApiFacade openApiFacade, ILogger logger) : base(learningHubHttpClient) { - this.facade = learningHubApiFacade; + this.facade = openApiFacade; } /// diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/OpenApiHttpClient.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/OpenApiHttpClient.cs new file mode 100644 index 000000000..5e8463cad --- /dev/null +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/OpenApiHttpClient.cs @@ -0,0 +1,39 @@ +namespace LearningHub.Nhs.AdminUI.Services +{ + using System.Net.Http; + using LearningHub.Nhs.AdminUI.Configuration; + using LearningHub.Nhs.AdminUI.Interfaces; + using LearningHub.Nhs.Caching; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Options; + + /// + /// The open api http client. + /// + public class OpenApiHttpClient : BaseHttpClient, IOpenApiHttpClient + { + /// + /// Initializes a new instance of the class. + /// + /// The http context accessor. + /// The web settings. + /// The http client. + /// The logger. + /// The cache service. + public OpenApiHttpClient( + IHttpContextAccessor httpContextAccessor, + IOptions webSettings, + HttpClient client, + ILogger logger, + ICacheService cacheService) + : base(httpContextAccessor, webSettings.Value, client, logger, cacheService) + { + } + + /// + /// Gets the open api url. + /// + public override string ApiUrl => this.WebSettings.OpenApiUrl; + } +} diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/ProviderService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/ProviderService.cs index eeb6976f9..cfdc4050b 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/ProviderService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/ProviderService.cs @@ -24,19 +24,20 @@ public class ProviderService : BaseService, IProviderService /// /// Defines the _facade. /// - private readonly ILearningHubApiFacade facade; + private readonly IOpenApiFacade facade; /// /// Initializes a new instance of the class. /// /// The cache service. /// Learning hub http client. - /// The learningHubApiFacade. - public ProviderService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, ILearningHubApiFacade learningHubApiFacade) + /// open api http client. + /// The openApiFacade. + public ProviderService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IOpenApiFacade openApiFacade) : base(learningHubHttpClient) { this.cacheService = cacheService; - this.facade = learningHubApiFacade; + this.facade = openApiFacade; } /// diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/ResourceService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/ResourceService.cs index 4c6e3fe46..038681c64 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/ResourceService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/ResourceService.cs @@ -24,8 +24,9 @@ public class ResourceService : BaseService, IResourceService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. - public ResourceService(ILearningHubHttpClient learningHubHttpClient) - : base(learningHubHttpClient) + /// The openApiHttpClient. + public ResourceService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient) + : base(learningHubHttpClient, openApiHttpClient) { } @@ -50,7 +51,7 @@ public async Task> GetResourc var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(pagingRequestModel); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); @@ -82,7 +83,7 @@ public async Task> GetResourceVersionEventsA { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionEvents/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -111,7 +112,7 @@ public async Task GetResourceVersionVa { ResourceVersionValidationResultViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionValidationResult/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -140,7 +141,7 @@ public async Task GetResourceVersionDevIdDetailsA { ResourceVersionDevIdViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionDevIdDetails/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -167,7 +168,7 @@ public async Task GetResourceVersionDevIdDetailsA /// The . public async Task DoesDevIdExistsAsync(string devId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DoesDevIdExists/{devId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -198,7 +199,7 @@ public async Task UpdateDevIdDetailsAsync(ResourceVersionDevIdViewModel model) var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateDevId"; var response = await client.PutAsync(request, stringContent).ConfigureAwait(false); @@ -223,7 +224,7 @@ public async Task GetResourceVersionExtendedVi { ResourceVersionExtendedViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionExtendedViewModel/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -252,7 +253,7 @@ public async Task> GetResourceVersionsAsync(int r { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersions/{resourceId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -283,7 +284,7 @@ public async Task RevertToDraft(int resourceVersion var json = JsonConvert.SerializeObject(new { resourceVersionId }); var stringContent = new StringContent(resourceVersionId.ToString(), Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/RevertToDraft"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -335,7 +336,7 @@ public async Task TransferResourceOwnership(int res var json = JsonConvert.SerializeObject(vm); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/TransferResourceOwnership"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -382,7 +383,7 @@ public async Task UnpublishResourceVersionAsync(int var json = JsonConvert.SerializeObject(vm); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UnpublishResourceVersion"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -433,7 +434,7 @@ public async Task CreateResourceVersionEvent(int re var json = JsonConvert.SerializeObject(vm); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/CreateResourceVersionEvent"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserGroupService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserGroupService.cs index 45dff59de..0a941c761 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserGroupService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserGroupService.cs @@ -32,15 +32,17 @@ public class UserGroupService : BaseService, IUserGroupService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The Open Api Http Client. /// The http context accessor. /// The cacheService. /// The roleService. public UserGroupService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, ICacheService cacheService, IRoleService roleService, IHttpContextAccessor contextAccessor) - : base(learningHubHttpClient) + : base(learningHubHttpClient, openApiHttpClient) { this.contextAccessor = contextAccessor; this.cacheService = cacheService; @@ -112,7 +114,7 @@ public async Task GetUserGroupAdminDetailbyIdAsyn { UserGroupAdminDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserGroupAdminDetailById/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -141,7 +143,7 @@ public async Task> GetUserGroupAdminRoleDetailByIdA { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserGroupAdminRoleDetailById/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -171,7 +173,7 @@ public async Task CreateUserGroup(UserGroupAdminDet var json = JsonConvert.SerializeObject(userGroup); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/CreateUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -214,7 +216,7 @@ public async Task UpdateUserGroup(UserGroupAdminDet var json = JsonConvert.SerializeObject(userGroup); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/UpdateUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -258,7 +260,7 @@ public async Task DeleteUserGroup(int userGroupId) var json = JsonConvert.SerializeObject(userGroup); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/DeleteUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -308,7 +310,7 @@ public async Task AddUsersToUserGroup(int userGroup var json = JsonConvert.SerializeObject(userUserGroups); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/AddUserUserGroups"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -359,7 +361,7 @@ public async Task AddUserGroupsToCatalogue(int cata var json = JsonConvert.SerializeObject(roleUserGroups); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/AddRoleUserGroups"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -403,7 +405,7 @@ public async Task DeleteUserUserGroup(int userUserG var json = JsonConvert.SerializeObject(userGroup); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/DeleteUserUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -447,7 +449,7 @@ public async Task DeleteRoleUserGroup(int roleUserG var json = JsonConvert.SerializeObject(roleUserGroupUpdate); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/DeleteRoleUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -502,7 +504,7 @@ public async Task> GetUserUserGroupPageAs var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter); var presetFilter = JsonConvert.SerializeObject(pagingRequestModel.PresetFilter); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserUserGroupAdminFilteredPage" + $"/{pagingRequestModel.Page}" @@ -551,7 +553,7 @@ public async Task> GetRoleUserGroupPageAs var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter); var presetFilter = JsonConvert.SerializeObject(pagingRequestModel.PresetFilter); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetRoleUserGroupAdminFilteredPage" + $"/{pagingRequestModel.Page}" @@ -598,7 +600,7 @@ private async Task> FetchRoleUserGroupDetailAsync() { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserGroupRoleDetail"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs index 7c64fd2c0..c84dbc2f2 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs +++ b/AdminUI/LearningHub.Nhs.AdminUI/Services/UserService.cs @@ -31,10 +31,11 @@ public class UserService : BaseService, IUserService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The openApiHttpClient . /// The CacheService . /// The userApiHttpClient . - public UserService(ILearningHubHttpClient learningHubHttpClient, ICacheService cacheService, IUserApiHttpClient userApiHttpClient) - : base(learningHubHttpClient) + public UserService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ICacheService cacheService, IUserApiHttpClient userApiHttpClient) + : base(learningHubHttpClient, openApiHttpClient) { this.cacheService = cacheService; this.userApiHttpClient = userApiHttpClient; @@ -166,7 +167,7 @@ public async Task GetEmailAddressRegistrationStatusAsyn var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter); var presetFilter = JsonConvert.SerializeObject(pagingRequestModel.PresetFilter); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/GetLHUserAdminBasicFilteredPage" + $"/{pagingRequestModel.Page}" @@ -274,7 +275,7 @@ public async Task> GetUserCon var modelString = JsonConvert.SerializeObject(pagingRequestModel); var content = new StringContent(modelString, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceAdminSearchFilteredPage"; @@ -459,7 +460,7 @@ public async Task AddUserGroupsToUser(int userId, s var json = JsonConvert.SerializeObject(userUserGroups); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/AddUserUserGroups"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -565,7 +566,7 @@ public async Task> GetUserLearni var filter = JsonConvert.SerializeObject(pagingRequestModel.Filter); var presetFilter = JsonConvert.SerializeObject(pagingRequestModel.PresetFilter); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserLearningRecord/GetUserLearningRecords" + $"/{pagingRequestModel.Page}" diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/Resource/Details.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/Resource/Details.cshtml index 53d548c59..a7a2942e8 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Views/Resource/Details.cshtml +++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/Resource/Details.cshtml @@ -571,6 +571,32 @@ } + @if (Model.ResourceTypeEnum == ResourceTypeEnum.Html) + { +
+
Resource Reference ID: @Model.DefaultResourceReferenceId
+
+
Resource Version Id
+
@Html.DisplayFor(model => model.ResourceVersionId)
+
Resource Type
+
+ @Html.DisplayFor(model => model.ResourceTypeDescription) +
+
ESR Link
+
@Model.HtmlDetails.HostedContentUrl
+ @if (Model.HtmlDetails.File != null) + { +
Zip File
+
+ @Model.HtmlDetails.File.FileName +
+ } + +
Content Folder
+
@Model.HtmlDetails.ContentFilePath
+
+
+ } @if (Model.ResourceTypeEnum == ResourceTypeEnum.Assessment) { diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_Layout.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_Layout.cshtml index aa098dc6a..d12be205a 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_Layout.cshtml +++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/Shared/_Layout.cshtml @@ -78,14 +78,7 @@ @**@ - @RenderSection("Scripts", required: false) - - diff --git a/AdminUI/LearningHub.Nhs.AdminUI/Views/UserGroup/_UsersModal.cshtml b/AdminUI/LearningHub.Nhs.AdminUI/Views/UserGroup/_UsersModal.cshtml index 1b05b917e..bdc123e89 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/Views/UserGroup/_UsersModal.cshtml +++ b/AdminUI/LearningHub.Nhs.AdminUI/Views/UserGroup/_UsersModal.cshtml @@ -41,10 +41,10 @@ { - @Html.ActionLink(item.Id.ToString(), "Details", new { id = item.Id }) + @Html.ActionLink(item.Id.ToString(), "Details", "User", new { id = item.Id }) - @Html.ActionLink(item.UserName.ToString(), "Details", new { id = item.Id }) + @Html.ActionLink(item.UserName.ToString(), "Details", "User", new { id = item.Id }) diff --git a/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json b/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json index b3a5c0f9c..95a04b8bc 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json +++ b/AdminUI/LearningHub.Nhs.AdminUI/appsettings.json @@ -17,6 +17,7 @@ "ELfhHubUrl": "", "LearningHubApiUrl": "", "UserApiUrl": "", + "OpenApiUrl": "", "LearningHubAdminUrl": "", "LogConfigDir": "D:\\learningHub\\NLog", "AuthenticationServiceUrl": "", diff --git a/AdminUI/LearningHub.Nhs.AdminUI/package-lock.json b/AdminUI/LearningHub.Nhs.AdminUI/package-lock.json index ccd742288..bbea60904 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/package-lock.json +++ b/AdminUI/LearningHub.Nhs.AdminUI/package-lock.json @@ -10,20 +10,20 @@ "dependencies": { "@ckeditor/ckeditor5-build-classic": "16.0.0", "@ckeditor/ckeditor5-vue": "1.0.3", - "@mediakind/mkplayer": "^1.21.0", + "@mediakind/mkplayer": "^1.22.0", "axios": "^0.30.0", "babel-polyfill": "^6.26.0", "bootstrap": "^4.6.2", "ckeditor4-vue": "^0.2.0", "concurrently": "^7.6.0", - "core-js": "^3.41.0", + "core-js": "^3.42.0", "js-cookie": "2.2.1", "lodash": "4.17.21", "moment": "^2.30.1", "navigator.sendbeacon": "0.0.20", "nhsuk-frontend": "^6.1.2", "openseadragon": "^2.4.2", - "sanitize-html": "^2.15.0", + "sanitize-html": "^2.17.0", "save": "^2.9.0", "ts-debounce": "2.3.0", "tus-js-client": "^2.3.2", @@ -40,8 +40,8 @@ "vuex": "^3.6.2" }, "devDependencies": { - "@babel/core": "^7.26.10", - "@babel/preset-env": "^7.26.9", + "@babel/core": "^7.27.3", + "@babel/preset-env": "^7.27.2", "@types/axios": "^0.14.0", "@types/bootstrap": "4.1.3", "@types/ckeditor": "4.9.10", @@ -49,9 +49,9 @@ "@types/jquery": "^3.3.32", "@types/jquery-match-height": "^0.7.8", "@types/js-cookie": "2.2.1", - "@types/lodash": "4.17.16", + "@types/lodash": "4.17.17", "@types/openseadragon": "^2.4.5", - "@types/sanitize-html": "^2.15.0", + "@types/sanitize-html": "^2.16.0", "@types/vuelidate": "^0.7.22", "@vue/babel-preset-app": "4.5.19", "@vue/test-utils": "^1.3.6", @@ -63,7 +63,7 @@ "css-loader": "^5.2.4", "file-loader": "^6.2.0", "jest": "^27.5.1", - "sass": "^1.86.3", + "sass": "^1.89.0", "sass-loader": "^11.0.1", "style-loader": "^2.0.0", "ts-jest": "^27.1.5", @@ -72,7 +72,7 @@ "vue-jest": "^3.0.7", "vue-loader": "^15.11.1", "vue-template-compiler": "^2.7.16", - "webpack": "^5.99.5", + "webpack": "^5.99.9", "webpack-cli": "^4.10.0", "webpack-dev-server": "^3.11.3" } @@ -92,24 +92,24 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.27.2.tgz", + "integrity": "sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ==", "dev": true, "license": "MIT", "engines": { @@ -117,22 +117,22 @@ } }, "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.27.3.tgz", + "integrity": "sha512-hyrN8ivxfvJ4i0fIJuV4EOlV0WDMz5Ui4StRTgVaAvWeiRCilXgwVvxJKtFQ3TKtHgJscB2YiXKGNJuVwhQMtA==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.3", + "@babel/parser": "^7.27.3", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.27.3", + "@babel/types": "^7.27.3", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -178,14 +178,14 @@ "dev": true }, "node_modules/@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.3.tgz", + "integrity": "sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", + "@babel/parser": "^7.27.3", + "@babel/types": "^7.27.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -195,27 +195,27 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.1.tgz", + "integrity": "sha512-WnuuDILl9oOBbKnb4L+DyODx7iC47XfzmNCpTttFsSp6hTG7XZxu60+4IO+2/hPfcGOoKbFiwoI/+zwARbNQow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -242,18 +242,18 @@ "license": "ISC" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", - "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", "semver": "^6.3.1" }, "engines": { @@ -264,13 +264,13 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz", - "integrity": "sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", "regexpu-core": "^6.2.0", "semver": "^6.3.1" }, @@ -324,43 +324,43 @@ "license": "MIT" }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -370,22 +370,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -393,15 +393,15 @@ } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-wrap-function": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -411,15 +411,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -429,40 +429,41 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -470,41 +471,41 @@ } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.3.tgz", + "integrity": "sha512-h/eKy9agOya1IGuLaZ9tEUgz+uIRXcbtOhRtUyyMf8JFmn1iT13vnl/IGVWSkdOCG/pC57U4S1jnAabAavTMwg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.3.tgz", + "integrity": "sha512-xyYxRj6+tLNDTWi0KCBcZ9V7yg3/lwL9DWh9Uwh/RIVlIfFidggcgxKX3GCXwCiswwcGRawBKbEg2LG/Y8eJhw==", "license": "MIT", "dependencies": { - "@babel/types": "^7.26.10" + "@babel/types": "^7.27.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -514,14 +515,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", - "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.27.1.tgz", + "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -531,13 +532,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", - "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", + "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -547,13 +548,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", - "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", + "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -563,15 +564,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", + "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -581,14 +582,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", - "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.27.1.tgz", + "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -723,13 +724,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz", - "integrity": "sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", + "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -739,12 +740,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -927,13 +929,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -943,15 +945,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.26.8.tgz", - "integrity": "sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.27.1.tgz", + "integrity": "sha512-eST9RrwlpaoJBDHShc+DS2SG4ATTi2MYNb4OxYkf3n+7eb49LWpnS+HSpVfW4x927qQwgk8A2hGNVaajAEw0EA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-remap-async-to-generator": "^7.25.9", - "@babel/traverse": "^7.26.8" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -961,15 +963,15 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", - "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", + "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-remap-async-to-generator": "^7.25.9" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-remap-async-to-generator": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -979,13 +981,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.26.5.tgz", - "integrity": "sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", + "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -995,13 +997,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", - "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.1.tgz", + "integrity": "sha512-QEcFlMl9nGTgh1rn2nIeU5bkfb9BAjaQcWbiP4LvKxUot52ABcTkpcyJ7f2Q2U2RuQ84BNLgts3jRme2dTx6Fw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1011,14 +1013,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", - "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", + "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1028,14 +1030,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz", - "integrity": "sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.27.1.tgz", + "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1045,17 +1047,17 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.27.1.tgz", + "integrity": "sha512-7iLhfFAubmpeJe/Wo2TVuDrykh/zlWXLzPNdL0Jqn/Xu8R3QQ8h9ff8FQoISZOsw74/HFqFI7NX63HN7QFIHKA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.27.1", "globals": "^11.1.0" }, "engines": { @@ -1066,14 +1068,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1083,13 +1085,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.27.1.tgz", + "integrity": "sha512-ttDCqhfvpE9emVkXbPD8vyxxh4TWYACVybGkDj+oReOGwnp066ITEivDlLwe0b1R0+evJ13IXQuLNB5w1fhC5Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1099,14 +1101,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", - "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", + "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1116,13 +1118,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", - "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", + "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1132,14 +1134,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1149,13 +1151,13 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", - "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", + "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1165,13 +1167,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1181,13 +1183,13 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", - "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", + "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1197,14 +1199,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", - "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1214,15 +1216,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1232,13 +1234,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", - "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", + "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1248,13 +1250,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1264,13 +1266,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", - "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.27.1.tgz", + "integrity": "sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1280,13 +1282,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", - "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", + "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1296,14 +1298,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", - "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", + "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1313,14 +1315,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1330,16 +1332,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", - "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.27.1.tgz", + "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1349,14 +1351,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", - "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", + "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1366,14 +1368,14 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", - "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", + "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1383,13 +1385,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", - "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", + "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1399,13 +1401,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.26.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.26.6.tgz", - "integrity": "sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", + "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1415,13 +1417,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", - "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", + "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1431,15 +1433,16 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", - "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.27.2.tgz", + "integrity": "sha512-AIUHD7xJ1mCrj3uPozvtngY3s0xpv7Nu7DoUSnzNY6Xam1Cy4rUznR//pvMHOhQ4AvbCexhbqXCtpxGHOGOO6g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9" + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1449,14 +1452,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", - "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", + "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1466,13 +1469,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", - "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", + "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1482,14 +1485,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", - "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.27.1.tgz", + "integrity": "sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1499,13 +1502,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.1.tgz", + "integrity": "sha512-018KRk76HWKeZ5l4oTj2zPpSh+NbGdt0st5S6x0pga6HgrjBOJb24mMDHorFopOOd6YHkLgOZ+zaCjZGPO4aKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1515,14 +1518,14 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", - "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", + "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1532,15 +1535,15 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", - "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", + "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1550,13 +1553,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", - "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", + "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1566,14 +1569,13 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", - "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.1.tgz", + "integrity": "sha512-B19lbbL7PMrKr52BNPjCqg1IyNUIjTcxKj8uX9zHO+PmWN93s19NDr/f69mIkEp2x9nmDJ08a7lgHaTTzvW7mw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "regenerator-transform": "^0.15.2" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1583,14 +1585,14 @@ } }, "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz", - "integrity": "sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", + "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1600,13 +1602,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", - "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", + "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1636,13 +1638,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1652,14 +1654,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1669,13 +1671,13 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1685,13 +1687,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", - "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1701,13 +1703,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.26.7.tgz", - "integrity": "sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", + "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1717,13 +1719,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", - "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", + "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1733,14 +1735,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", - "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", + "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1750,14 +1752,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1767,14 +1769,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", - "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", + "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -1784,75 +1786,75 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.26.9.tgz", - "integrity": "sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.27.2.tgz", + "integrity": "sha512-Ma4zSuYSlGNRlCLO+EAzLnCmJK2vdstgv+n7aUP+/IKZrOfWHOJVdSJtuub8RzHTj3ahD37k5OKJWvzf16TQyQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", + "@babel/compat-data": "^7.27.2", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.27.1", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.27.1", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.26.0", - "@babel/plugin-syntax-import-attributes": "^7.26.0", + "@babel/plugin-syntax-import-assertions": "^7.27.1", + "@babel/plugin-syntax-import-attributes": "^7.27.1", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.9", - "@babel/plugin-transform-async-generator-functions": "^7.26.8", - "@babel/plugin-transform-async-to-generator": "^7.25.9", - "@babel/plugin-transform-block-scoped-functions": "^7.26.5", - "@babel/plugin-transform-block-scoping": "^7.25.9", - "@babel/plugin-transform-class-properties": "^7.25.9", - "@babel/plugin-transform-class-static-block": "^7.26.0", - "@babel/plugin-transform-classes": "^7.25.9", - "@babel/plugin-transform-computed-properties": "^7.25.9", - "@babel/plugin-transform-destructuring": "^7.25.9", - "@babel/plugin-transform-dotall-regex": "^7.25.9", - "@babel/plugin-transform-duplicate-keys": "^7.25.9", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-dynamic-import": "^7.25.9", - "@babel/plugin-transform-exponentiation-operator": "^7.26.3", - "@babel/plugin-transform-export-namespace-from": "^7.25.9", - "@babel/plugin-transform-for-of": "^7.26.9", - "@babel/plugin-transform-function-name": "^7.25.9", - "@babel/plugin-transform-json-strings": "^7.25.9", - "@babel/plugin-transform-literals": "^7.25.9", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", - "@babel/plugin-transform-member-expression-literals": "^7.25.9", - "@babel/plugin-transform-modules-amd": "^7.25.9", - "@babel/plugin-transform-modules-commonjs": "^7.26.3", - "@babel/plugin-transform-modules-systemjs": "^7.25.9", - "@babel/plugin-transform-modules-umd": "^7.25.9", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", - "@babel/plugin-transform-new-target": "^7.25.9", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.26.6", - "@babel/plugin-transform-numeric-separator": "^7.25.9", - "@babel/plugin-transform-object-rest-spread": "^7.25.9", - "@babel/plugin-transform-object-super": "^7.25.9", - "@babel/plugin-transform-optional-catch-binding": "^7.25.9", - "@babel/plugin-transform-optional-chaining": "^7.25.9", - "@babel/plugin-transform-parameters": "^7.25.9", - "@babel/plugin-transform-private-methods": "^7.25.9", - "@babel/plugin-transform-private-property-in-object": "^7.25.9", - "@babel/plugin-transform-property-literals": "^7.25.9", - "@babel/plugin-transform-regenerator": "^7.25.9", - "@babel/plugin-transform-regexp-modifiers": "^7.26.0", - "@babel/plugin-transform-reserved-words": "^7.25.9", - "@babel/plugin-transform-shorthand-properties": "^7.25.9", - "@babel/plugin-transform-spread": "^7.25.9", - "@babel/plugin-transform-sticky-regex": "^7.25.9", - "@babel/plugin-transform-template-literals": "^7.26.8", - "@babel/plugin-transform-typeof-symbol": "^7.26.7", - "@babel/plugin-transform-unicode-escapes": "^7.25.9", - "@babel/plugin-transform-unicode-property-regex": "^7.25.9", - "@babel/plugin-transform-unicode-regex": "^7.25.9", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "@babel/plugin-transform-async-generator-functions": "^7.27.1", + "@babel/plugin-transform-async-to-generator": "^7.27.1", + "@babel/plugin-transform-block-scoped-functions": "^7.27.1", + "@babel/plugin-transform-block-scoping": "^7.27.1", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.27.1", + "@babel/plugin-transform-classes": "^7.27.1", + "@babel/plugin-transform-computed-properties": "^7.27.1", + "@babel/plugin-transform-destructuring": "^7.27.1", + "@babel/plugin-transform-dotall-regex": "^7.27.1", + "@babel/plugin-transform-duplicate-keys": "^7.27.1", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-dynamic-import": "^7.27.1", + "@babel/plugin-transform-exponentiation-operator": "^7.27.1", + "@babel/plugin-transform-export-namespace-from": "^7.27.1", + "@babel/plugin-transform-for-of": "^7.27.1", + "@babel/plugin-transform-function-name": "^7.27.1", + "@babel/plugin-transform-json-strings": "^7.27.1", + "@babel/plugin-transform-literals": "^7.27.1", + "@babel/plugin-transform-logical-assignment-operators": "^7.27.1", + "@babel/plugin-transform-member-expression-literals": "^7.27.1", + "@babel/plugin-transform-modules-amd": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-modules-systemjs": "^7.27.1", + "@babel/plugin-transform-modules-umd": "^7.27.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", + "@babel/plugin-transform-new-target": "^7.27.1", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", + "@babel/plugin-transform-numeric-separator": "^7.27.1", + "@babel/plugin-transform-object-rest-spread": "^7.27.2", + "@babel/plugin-transform-object-super": "^7.27.1", + "@babel/plugin-transform-optional-catch-binding": "^7.27.1", + "@babel/plugin-transform-optional-chaining": "^7.27.1", + "@babel/plugin-transform-parameters": "^7.27.1", + "@babel/plugin-transform-private-methods": "^7.27.1", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@babel/plugin-transform-property-literals": "^7.27.1", + "@babel/plugin-transform-regenerator": "^7.27.1", + "@babel/plugin-transform-regexp-modifiers": "^7.27.1", + "@babel/plugin-transform-reserved-words": "^7.27.1", + "@babel/plugin-transform-shorthand-properties": "^7.27.1", + "@babel/plugin-transform-spread": "^7.27.1", + "@babel/plugin-transform-sticky-regex": "^7.27.1", + "@babel/plugin-transform-template-literals": "^7.27.1", + "@babel/plugin-transform-typeof-symbol": "^7.27.1", + "@babel/plugin-transform-unicode-escapes": "^7.27.1", + "@babel/plugin-transform-unicode-property-regex": "^7.27.1", + "@babel/plugin-transform-unicode-regex": "^7.27.1", + "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.11.0", @@ -1912,32 +1914,32 @@ "dev": true }, "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.3.tgz", + "integrity": "sha512-lId/IfN/Ye1CIu8xG7oKBHXd2iNb2aW1ilPszzGcJug6M8RCKfVNcYhpI5+bMvFYjK7lXIM0R+a+6r8xhHp2FQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.27.3", + "@babel/parser": "^7.27.3", + "@babel/template": "^7.27.2", + "@babel/types": "^7.27.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1969,13 +1971,13 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.3.tgz", + "integrity": "sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -3373,9 +3375,9 @@ } }, "node_modules/@mediakind/mkplayer": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@mediakind/mkplayer/-/mkplayer-1.21.0.tgz", - "integrity": "sha512-6sZwxQObISgmD4z0RV6xoi2bJgnOBtDAa2bPg4H/D095MaUInaDkrCimROst/rWfeMFg2m4h9PSmJV88cYbvQw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@mediakind/mkplayer/-/mkplayer-1.22.0.tgz", + "integrity": "sha512-1PWswbIw3U84QkRWbkCVDha0qppzrpDbxiytnRFkLeUpE8klKRWJtI92ph0favspfTFjanX8A0qTGRkA8lsLwA==", "license": "©2025 Copyright Mediakind Ltd. All Rights Reserved. Including All Downloadable Materials.", "dependencies": { "bitmovin-player": "8.193.0", @@ -3949,15 +3951,16 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.16", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", - "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", + "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", "dev": true, "license": "MIT" }, @@ -3986,9 +3989,9 @@ "dev": true }, "node_modules/@types/sanitize-html": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.15.0.tgz", - "integrity": "sha512-71Z6PbYsVKfp4i6Jvr37s5ql6if1Q/iJQT80NbaSi7uGaG8CqBMXP0pk/EsURAOuGdk5IJCd/vnzKrR7S3Txsw==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.16.0.tgz", + "integrity": "sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==", "dev": true, "license": "MIT", "dependencies": { @@ -4060,12 +4063,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/@types/vuelidate/node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, "node_modules/@types/vuelidate/node_modules/postcss": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", @@ -4255,12 +4252,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/@vue/babel-plugin-resolve-type/node_modules/postcss/node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, "node_modules/@vue/babel-plugin-resolve-type/node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7249,9 +7240,9 @@ } }, "node_modules/core-js": { - "version": "3.41.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.41.0.tgz", - "integrity": "sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==", + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.42.0.tgz", + "integrity": "sha512-Sz4PP4ZA+Rq4II21qkNqOEDTDrCvcANId3xpIgB34NDkWc3UduWj2dqEtN9yZIq8Dk3HyPI33x9sqqU5C8sr0g==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -15043,9 +15034,10 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" }, "node_modules/picomatch": { "version": "2.2.3", @@ -15673,16 +15665,6 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -15959,9 +15941,9 @@ "dev": true }, "node_modules/sanitize-html": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.15.0.tgz", - "integrity": "sha512-wIjst57vJGpLyBP8ioUbg6ThwJie5SuSIjHxJg53v5Fg+kUK+AXlb7bK3RNXpp315MvwM+0OBGCV6h5pPHsVhA==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz", + "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", "license": "MIT", "dependencies": { "deepmerge": "^4.2.2", @@ -16008,11 +15990,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/sanitize-html/node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" - }, "node_modules/sanitize-html/node_modules/postcss": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz", @@ -16049,9 +16026,9 @@ } }, "node_modules/sass": { - "version": "1.86.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.86.3.tgz", - "integrity": "sha512-iGtg8kus4GrsGLRDLRBRHY9dNVA78ZaS7xr01cWnS7PEMQyFtTqBiyCrfpTYTZXRWM94akzckYjh8oADfFNTzw==", + "version": "1.89.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.89.0.tgz", + "integrity": "sha512-ld+kQU8YTdGNjOLfRWBzewJpU5cwEv/h5yyqlSeJcj6Yh8U4TDA9UA5FPicqDz/xgRPWRSYIQNiFks21TbA9KQ==", "dev": true, "license": "MIT", "dependencies": { @@ -17921,12 +17898,6 @@ "node": ">=6" } }, - "node_modules/update-browserslist-db/node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -18290,14 +18261,15 @@ } }, "node_modules/webpack": { - "version": "5.99.5", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.5.tgz", - "integrity": "sha512-q+vHBa6H9qwBLUlHL4Y7L0L1/LlyBKZtS9FHNCQmtayxjI5RKC9yD8gpvLeqGv5lCQp1Re04yi0MF40pf30Pvg==", + "version": "5.99.9", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz", + "integrity": "sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", @@ -18314,7 +18286,7 @@ "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^4.3.0", + "schema-utils": "^4.3.2", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.3.11", "watchpack": "^2.4.1", @@ -19076,9 +19048,9 @@ "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.0.tgz", - "integrity": "sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz", + "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==", "dev": true, "license": "MIT", "dependencies": { diff --git a/AdminUI/LearningHub.Nhs.AdminUI/package.json b/AdminUI/LearningHub.Nhs.AdminUI/package.json index 4240aeef9..2117d7501 100644 --- a/AdminUI/LearningHub.Nhs.AdminUI/package.json +++ b/AdminUI/LearningHub.Nhs.AdminUI/package.json @@ -22,20 +22,20 @@ "dependencies": { "@ckeditor/ckeditor5-build-classic": "16.0.0", "@ckeditor/ckeditor5-vue": "1.0.3", - "@mediakind/mkplayer": "^1.21.0", + "@mediakind/mkplayer": "^1.22.0", "axios": "^0.30.0", "babel-polyfill": "^6.26.0", "bootstrap": "^4.6.2", "ckeditor4-vue": "^0.2.0", "concurrently": "^7.6.0", - "core-js": "^3.41.0", + "core-js": "^3.42.0", "js-cookie": "2.2.1", "lodash": "4.17.21", "moment": "^2.30.1", "navigator.sendbeacon": "0.0.20", "nhsuk-frontend": "^6.1.2", "openseadragon": "^2.4.2", - "sanitize-html": "^2.15.0", + "sanitize-html": "^2.17.0", "save": "^2.9.0", "ts-debounce": "2.3.0", "tus-js-client": "^2.3.2", @@ -52,8 +52,8 @@ "vuex": "^3.6.2" }, "devDependencies": { - "@babel/preset-env": "^7.26.9", - "@babel/core": "^7.26.10", + "@babel/preset-env": "^7.27.2", + "@babel/core": "^7.27.3", "@types/axios": "^0.14.0", "@types/bootstrap": "4.1.3", "@types/ckeditor": "4.9.10", @@ -61,9 +61,9 @@ "@types/jquery": "^3.3.32", "@types/jquery-match-height": "^0.7.8", "@types/js-cookie": "2.2.1", - "@types/lodash": "4.17.16", + "@types/lodash": "4.17.17", "@types/openseadragon": "^2.4.5", - "@types/sanitize-html": "^2.15.0", + "@types/sanitize-html": "^2.16.0", "@types/vuelidate": "^0.7.22", "@vue/babel-preset-app": "4.5.19", "@vue/test-utils": "^1.3.6", @@ -75,7 +75,7 @@ "css-loader": "^5.2.4", "file-loader": "^6.2.0", "jest": "^27.5.1", - "sass": "^1.86.3", + "sass": "^1.89.0", "sass-loader": "^11.0.1", "style-loader": "^2.0.0", "ts-jest": "^27.1.5", @@ -84,7 +84,7 @@ "vue-jest": "^3.0.7", "vue-loader": "^15.11.1", "vue-template-compiler": "^2.7.16", - "webpack": "^5.99.5", + "webpack": "^5.99.9", "webpack-cli": "^4.10.0", "webpack-dev-server": "^3.11.3" } diff --git a/AdminUI/LearningHub.Nhs.AdminUI/web.config b/AdminUI/LearningHub.Nhs.AdminUI/web.config deleted file mode 100644 index 6bcb74972..000000000 --- a/AdminUI/LearningHub.Nhs.AdminUI/web.config +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/AdminUI/LearningHub.Nhs.AdminUI/wwwroot/js/PageUnload.js b/AdminUI/LearningHub.Nhs.AdminUI/wwwroot/js/PageUnload.js deleted file mode 100644 index 8c458bee1..000000000 --- a/AdminUI/LearningHub.Nhs.AdminUI/wwwroot/js/PageUnload.js +++ /dev/null @@ -1,13 +0,0 @@ - // This function will be called when the browser window is closed or unloaded - function tellServerBrowserClosed() { - // Send an asynchronous request to the server when the browser is closed - fetch('/api/user/browser-close', { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify({ message: 'Browser closed' }) - }) - .then(response => response.json()) - .catch(error => console.error('Error sending data to server:', error)); - } \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 709a8ce13..c3a7f4e28 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -4,7 +4,7 @@ $(SolutionDir)StyleCop.ruleset - +
\ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 000000000..59413f8ea --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,93 @@ + + + + + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj index d6bf3cd0d..1569f9734 100644 --- a/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj +++ b/LearningHub.Nhs.WebUI.AutomatedUiTests/LearningHub.Nhs.WebUI.AutomatedUiTests.csproj @@ -1,37 +1,37 @@ - + - - net8.0 - enable - enable + + net8.0 + enable + enable - false + false - True - + True + - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + - - - + + + diff --git a/LearningHub.Nhs.WebUI.sln b/LearningHub.Nhs.WebUI.sln index 5aea6885f..55cce01f0 100644 --- a/LearningHub.Nhs.WebUI.sln +++ b/LearningHub.Nhs.WebUI.sln @@ -8,6 +8,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B5D48B6A-D4A7-494E-89C0-64428232D242}" ProjectSection(SolutionItems) = preProject Directory.Build.props = Directory.Build.props + Directory.Packages.props = Directory.Packages.props StyleCop.ruleset = StyleCop.ruleset EndProjectSection EndProject diff --git a/LearningHub.Nhs.WebUI/Configuration/Settings.cs b/LearningHub.Nhs.WebUI/Configuration/Settings.cs index f0f2da3c1..e300e80e3 100644 --- a/LearningHub.Nhs.WebUI/Configuration/Settings.cs +++ b/LearningHub.Nhs.WebUI/Configuration/Settings.cs @@ -31,6 +31,11 @@ public Settings() /// public string LearningHubApiUrl { get; set; } + /// + /// Gets or sets the OpenApiUrl. + /// + public string OpenApiUrl { get; set; } + /// /// Gets or sets the UserApiUrl. /// @@ -196,11 +201,6 @@ public Settings() /// public int PasswordRequestLimit { get; set; } - /// - /// Gets or sets the ConcurrentId. - /// - public int ConcurrentId { get; set; } - /// /// Gets or sets the SupportUrls. /// diff --git a/LearningHub.Nhs.WebUI/Controllers/Api/UserController.cs b/LearningHub.Nhs.WebUI/Controllers/Api/UserController.cs index 48f2c0e9e..1f5330bbe 100644 --- a/LearningHub.Nhs.WebUI/Controllers/Api/UserController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/Api/UserController.cs @@ -63,26 +63,6 @@ public async Task CurrentProfile() return this.Ok(await this.userService.GetCurrentUserProfileAsync()); } - /// - /// The SessionTimeout. - /// - /// The . - [HttpPost("browser-close")] - public IActionResult BrowserClose() - { - // Add browser close to the UserHistory - UserHistoryViewModel userHistory = new UserHistoryViewModel() - { - UserId = this.CurrentUserId, - UserHistoryTypeId = (int)UserHistoryType.Logout, - Detail = @"User browser closed", - }; - - this.userService.StoreUserHistory(userHistory); - - return this.Ok(true); - } - /// /// Get current user's basic details. /// @@ -122,13 +102,13 @@ public async Task CheckUserRole() /// /// to check user password is correct. /// - /// The currentPassword. + /// The currentPassword. /// The . - [HttpGet] - [Route("ConfirmPassword/{currentPassword}")] - public async Task ConfirmPassword(string currentPassword) + [HttpPost] + [Route("ConfirmPassword")] + public async Task ConfirmPassword([FromBody] PasswordUpdateModel password) { - string passwordHash = this.userService.Base64MD5HashDigest(currentPassword); + string passwordHash = this.userService.Base64MD5HashDigest(password.PasswordHash); var userPersonalDetails = await this.userService.GetCurrentUserPersonalDetailsAsync(); if (userPersonalDetails != null && userPersonalDetails.PasswordHash == passwordHash) { diff --git a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs index 9b91ed9ac..d5f53c00d 100644 --- a/LearningHub.Nhs.WebUI/Controllers/HomeController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/HomeController.cs @@ -6,7 +6,6 @@ namespace LearningHub.Nhs.WebUI.Controllers using System.Linq; using System.Net.Http; using System.Threading.Tasks; - using AspNetCoreRateLimit; using elfhHub.Nhs.Models.Common; using elfhHub.Nhs.Models.Enums; using LearningHub.Nhs.Models.Content; @@ -27,7 +26,6 @@ namespace LearningHub.Nhs.WebUI.Controllers using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.FeatureManagement; - using UAParser; using Settings = LearningHub.Nhs.WebUI.Configuration.Settings; /// @@ -42,6 +40,7 @@ public class HomeController : BaseController private readonly IDashboardService dashboardService; private readonly IContentService contentService; private readonly IFeatureManager featureManager; + private readonly IUserGroupService userGroupService; private readonly Microsoft.Extensions.Configuration.IConfiguration configuration; /// @@ -57,6 +56,7 @@ public class HomeController : BaseController /// Dashboard service. /// Content service. /// featureManager. + /// userGroupService. /// config. public HomeController( IHttpClientFactory httpClientFactory, @@ -69,6 +69,7 @@ public HomeController( IDashboardService dashboardService, IContentService contentService, IFeatureManager featureManager, + IUserGroupService userGroupService, Microsoft.Extensions.Configuration.IConfiguration configuration) : base(hostingEnvironment, httpClientFactory, logger, settings.Value) { @@ -78,6 +79,7 @@ public HomeController( this.dashboardService = dashboardService; this.contentService = contentService; this.featureManager = featureManager; + this.userGroupService = userGroupService; this.configuration = configuration; } @@ -208,54 +210,44 @@ public async Task Index(string myLearningDashboard = "my-in-progr { if (this.User?.Identity.IsAuthenticated == true) { - var userHistoryDetail = await this.userService.CheckUserHasAnActiveSessionAsync(this.CurrentUserId); - var uaParser = Parser.GetDefault(); - var clientInfo = uaParser.Parse(this.Request.Headers["User-Agent"]); - - if (userHistoryDetail.Items.Count == 0 || userHistoryDetail.Items[0].BrowserName == clientInfo.UA.Family) + this.Logger.LogInformation("User is authenticated: User is {fullname} and userId is: {lhuserid}", this.User.Identity.GetCurrentName(), this.User.Identity.GetCurrentUserId()); + if (this.User.IsInRole("Administrator") || this.User.IsInRole("BlueUser") || this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser")) { - this.Settings.ConcurrentId = this.CurrentUserId; - this.Logger.LogInformation("User is authenticated: User is {fullname} and userId is: {lhuserid}", this.User.Identity.GetCurrentName(), this.User.Identity.GetCurrentUserId()); - if (this.User.IsInRole("Administrator") || this.User.IsInRole("BlueUser") || this.User.IsInRole("ReadOnly") || this.User.IsInRole("BasicUser")) + var learningTask = this.dashboardService.GetMyAccessLearningsAsync(myLearningDashboard, 1); + var resourcesTask = this.dashboardService.GetResourcesAsync(resourceDashboard, 1); + var cataloguesTask = this.dashboardService.GetCataloguesAsync(catalogueDashboard, 1); + var userGroupsTask = this.userGroupService.UserHasCatalogueContributionPermission(); + + var enrolledCoursesTask = Task.FromResult(new List()); + var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result; + this.ViewBag.EnableMoodle = enableMoodle; + this.ViewBag.ValidMoodleUser = this.CurrentMoodleUserId > 0; + if (enableMoodle && myLearningDashboard == "my-enrolled-courses") { - var learningTask = this.dashboardService.GetMyAccessLearningsAsync(myLearningDashboard, 1); - var resourcesTask = this.dashboardService.GetResourcesAsync(resourceDashboard, 1); - var cataloguesTask = this.dashboardService.GetCataloguesAsync(catalogueDashboard, 1); - - var enrolledCoursesTask = Task.FromResult(new List()); - var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result; - this.ViewBag.EnableMoodle = enableMoodle; - this.ViewBag.ValidMoodleUser = this.CurrentMoodleUserId > 0; - if (enableMoodle && myLearningDashboard == "my-enrolled-courses") - { - enrolledCoursesTask = this.dashboardService.GetEnrolledCoursesFromMoodleAsync(this.CurrentMoodleUserId, 1); - } - - await Task.WhenAll(learningTask, resourcesTask, cataloguesTask); - - var model = new DashboardViewModel() - { - MyLearnings = await learningTask, - Resources = await resourcesTask, - Catalogues = await cataloguesTask, - EnrolledCourses = await enrolledCoursesTask, - }; - - if (!string.IsNullOrEmpty(this.Request.Query["preview"]) && Convert.ToBoolean(this.Request.Query["preview"])) - { - return this.View("LandingPage", await this.GetLandingPageContent(Convert.ToBoolean(this.Request.Query["preview"]))); - } - - return this.View("Dashboard", model); + enrolledCoursesTask = this.dashboardService.GetEnrolledCoursesFromMoodleAsync(this.CurrentMoodleUserId, 1); } - else + + await Task.WhenAll(learningTask, resourcesTask, cataloguesTask, userGroupsTask); + + var model = new DashboardViewModel() { - return this.RedirectToAction("InvalidUserAccount", "Account"); + MyLearnings = await learningTask, + Resources = await resourcesTask, + Catalogues = await cataloguesTask, + EnrolledCourses = await enrolledCoursesTask, + }; + var userHasContributePermission = await userGroupsTask; + this.ViewBag.userHasContributePermission = userHasContributePermission; + if (!string.IsNullOrEmpty(this.Request.Query["preview"]) && Convert.ToBoolean(this.Request.Query["preview"])) + { + return this.View("LandingPage", await this.GetLandingPageContent(Convert.ToBoolean(this.Request.Query["preview"]))); } + + return this.View("Dashboard", model); } else { - return this.RedirectToAction("AlreadyAnActiveSession", "Account"); + return this.RedirectToAction("InvalidUserAccount", "Account"); } } else @@ -288,6 +280,10 @@ public async Task LoadPage(string dashBoardTray = "my-learning", Catalogues = new Nhs.Models.Dashboard.DashboardCatalogueResponseViewModel { Type = catalogueDashBoard }, }; + var enableMoodle = Task.Run(() => this.featureManager.IsEnabledAsync(FeatureFlags.EnableMoodle)).Result; + this.ViewBag.EnableMoodle = enableMoodle; + this.ViewBag.ValidMoodleUser = this.CurrentMoodleUserId > 0; + bool isAjax = this.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest"; if (isAjax) @@ -382,7 +378,7 @@ public IActionResult UserLogout() [AllowAnonymous] public IActionResult Logout() { - var redirectUri = $"{this.configuration["LearningHubAuthServiceConfig:Authority"]}/Home/SetIsPasswordUpdate?isLogout=true"; + var redirectUri = $"{this.configuration["LearningHubAuthServiceConfig:Authority"]}/Home/SetIsPasswordUpdate?isPasswordUpdate=false"; return this.Redirect(redirectUri); } @@ -399,41 +395,12 @@ public IActionResult SessionTimeout(string returnUrl = "/") return this.Redirect(returnUrl); } - // Add successful logout to the UserHistory - UserHistoryViewModel userHistory = new UserHistoryViewModel() - { - UserId = this.Settings.ConcurrentId, - UserHistoryTypeId = (int)UserHistoryType.Logout, - Detail = @"User session time out", - }; - - this.userService.StoreUserHistory(userHistory); - this.ViewBag.AuthTimeout = this.authConfig.AuthTimeout; this.ViewBag.ReturnUrl = returnUrl; return this.View(); } - /// - /// The SessionTimeout. - /// - /// The . - [HttpPost("browser-close")] - public IActionResult BrowserClose() - { - // Add browser close to the UserHistory - UserHistoryViewModel userHistory = new UserHistoryViewModel() - { - UserId = this.CurrentUserId, - UserHistoryTypeId = (int)UserHistoryType.Logout, - Detail = @"User browser closed", - }; - - this.userService.StoreUserHistory(userHistory); - return this.Ok(true); - } - /// /// The SitemapXml. /// diff --git a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs index 8711dd817..d1dadb902 100644 --- a/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/MyAccountController.cs @@ -458,7 +458,7 @@ public async Task UpdatePassword(ChangePasswordViewModel model) if (this.ModelState.IsValid) { await this.userService.UpdatePassword(model.NewPassword); - var redirectUri = $"{this.configuration["LearningHubAuthServiceConfig:Authority"]}/Home/SetIsPasswordUpdate?isLogout=false"; + var redirectUri = $"{this.configuration["LearningHubAuthServiceConfig:Authority"]}/Home/SetIsPasswordUpdate?isPasswordUpdate=true"; return this.Redirect(redirectUri); } else @@ -678,29 +678,37 @@ public async Task ChangeCurrentRole([FromQuery] UserJobRoleUpdate return this.View("ChangeCurrentRole", viewModel); } - if (formSubmission && viewModel.SelectedJobRoleId.HasValue) + if (!string.IsNullOrWhiteSpace(viewModel.FilterText)) { - var newRoleId = viewModel.SelectedJobRoleId.Value; - var jobRole = await this.jobRoleService.GetByIdAsync(newRoleId); + var jobRoles = await this.jobRoleService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize); + viewModel.RoleList = jobRoles.Item2; + viewModel.TotalItems = jobRoles.Item1; + viewModel.HasItems = jobRoles.Item1 > 0; + } - if (jobRole.MedicalCouncilId > 0 && jobRole.MedicalCouncilId < 4) + if (formSubmission) + { + if (viewModel.SelectedJobRoleId.HasValue) { - return this.RedirectToAction(nameof(this.ChangeMedicalCouncilNo), new UserMedicalCouncilNoUpdateViewModel { SelectedJobRoleId = newRoleId }); + var newRoleId = viewModel.SelectedJobRoleId.Value; + var jobRole = await this.jobRoleService.GetByIdAsync(newRoleId); + + if (jobRole.MedicalCouncilId > 0 && jobRole.MedicalCouncilId < 4) + { + return this.RedirectToAction(nameof(this.ChangeMedicalCouncilNo), new UserMedicalCouncilNoUpdateViewModel { SelectedJobRoleId = newRoleId }); + } + else + { + return this.RedirectToAction(nameof(this.ChangeGrade), new UserGradeUpdateViewModel { SelectedJobRoleId = newRoleId }); + } } else { - return this.RedirectToAction(nameof(this.ChangeGrade), new UserGradeUpdateViewModel { SelectedJobRoleId = newRoleId }); + this.ModelState.AddModelError(nameof(viewModel.SelectedJobRoleId), CommonValidationErrorMessages.RoleRequired); + return this.View("ChangeCurrentRole", viewModel); } } - if (!string.IsNullOrWhiteSpace(viewModel.FilterText)) - { - var jobRoles = await this.jobRoleService.GetPagedFilteredAsync(viewModel.FilterText, viewModel.CurrentPage, viewModel.PageSize); - viewModel.RoleList = jobRoles.Item2; - viewModel.TotalItems = jobRoles.Item1; - viewModel.HasItems = jobRoles.Item1 > 0; - } - return this.View("ChangeCurrentRole", viewModel); } @@ -800,26 +808,37 @@ public async Task ChangeGrade([FromQuery] UserGradeUpdateViewMode viewModel.Grade = profile.Grade; viewModel.SelectedJobRole = jobRole.NameWithStaffGroup; viewModel.SelectedMedicalCouncilId = jobRole.MedicalCouncilId; - - if (this.User.IsInRole("BasicUser") || (formSubmission && viewModel.SelectedGradeId.HasValue)) + if (formSubmission) { - var medicalCouncilNoRequired = jobRole.MedicalCouncilId > 0 && jobRole.MedicalCouncilId < 4; - await this.userService.UpdateUserEmployment( - new elfhHub.Nhs.Models.Entities.UserEmployment - { - Id = profile.EmploymentId, - UserId = profile.Id, - JobRoleId = viewModel.SelectedJobRoleId, - MedicalCouncilId = medicalCouncilNoRequired ? jobRole.MedicalCouncilId : null, - MedicalCouncilNo = medicalCouncilNoRequired ? (viewModel.SelectedMedicalCouncilNo ?? profile.MedicalCouncilNo) : null, - GradeId = viewModel.SelectedGradeId, - SpecialtyId = profile.SpecialtyId, - StartDate = profile.JobStartDate, - LocationId = profile.LocationId, - }); + if (this.User.IsInRole("BasicUser") || viewModel.SelectedGradeId != null) + { + var medicalCouncilNoRequired = jobRole.MedicalCouncilId > 0 && jobRole.MedicalCouncilId < 4; + await this.userService.UpdateUserEmployment( + new elfhHub.Nhs.Models.Entities.UserEmployment + { + Id = profile.EmploymentId, + UserId = profile.Id, + JobRoleId = viewModel.SelectedJobRoleId, + MedicalCouncilId = medicalCouncilNoRequired ? jobRole.MedicalCouncilId : null, + MedicalCouncilNo = medicalCouncilNoRequired ? (viewModel.SelectedMedicalCouncilNo ?? profile.MedicalCouncilNo) : null, + GradeId = Convert.ToInt32(viewModel.SelectedGradeId), + SpecialtyId = profile.SpecialtyId, + StartDate = profile.JobStartDate, + LocationId = profile.LocationId, + }); - this.ViewBag.SuccessMessage = "Your job details have been changed"; - return this.View("SuccessMessage"); + this.ViewBag.SuccessMessage = "Your job details have been changed"; + return this.View("SuccessMessage"); + } + else + { + this.ModelState.AddModelError(nameof(viewModel.SelectedGradeId), CommonValidationErrorMessages.GradeRequired); + return this.View("ChangeGrade", viewModel); + } + } + else + { + viewModel.SelectedGradeId = profile.GradeId.ToString(); } return this.View("ChangeGrade", viewModel); diff --git a/LearningHub.Nhs.WebUI/Controllers/SearchController.cs b/LearningHub.Nhs.WebUI/Controllers/SearchController.cs index ff1afba0d..a7b53fb11 100644 --- a/LearningHub.Nhs.WebUI/Controllers/SearchController.cs +++ b/LearningHub.Nhs.WebUI/Controllers/SearchController.cs @@ -81,7 +81,7 @@ public async Task Index(SearchRequestViewModel search, bool noSor if (filterApplied) { - await this.searchService.RegisterSearchEventsAsync(search, SearchFormActionTypeEnum.ApplyFilter, searchResult.ResourceSearchResult.TotalHits); + await this.searchService.RegisterSearchEventsAsync(search, SearchFormActionTypeEnum.ApplyFilter, searchResult.ResourceSearchResult?.TotalHits ?? 0); } if (noSortFilterError) diff --git a/LearningHub.Nhs.WebUI/Helpers/IOpenApiFacade.cs b/LearningHub.Nhs.WebUI/Helpers/IOpenApiFacade.cs new file mode 100644 index 000000000..a603461c7 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Helpers/IOpenApiFacade.cs @@ -0,0 +1,59 @@ +namespace LearningHub.Nhs.WebUI.Helpers +{ + using System.Threading.Tasks; + using LearningHub.Nhs.Models.Common; + + /// + /// Defines the . + /// + public interface IOpenApiFacade + { + /// + /// The GetAsync. + /// + /// The type. + /// The url. + /// The . + Task GetAsync(string url) + where T : class, new(); + + /// + /// The PostAsync. + /// + /// The type. + /// The url. + /// The body. + /// The . + Task PostAsync(string url, T body) + where T : class, new(); + + /// + /// The PostAsync. + /// + /// The type. + /// . + /// The url. + /// The body. + /// The . + Task PostAsync(string url, TBody body) + where T : class, new() + where TBody : class, new(); + + /// + /// The PutAsync. + /// + /// The url. + /// The . + Task PutAsync(string url); + + /// + /// The PutAsync. + /// + /// . + /// The url. + /// The body. + /// The . + Task PutAsync(string url, T body) + where T : class, new(); + } +} diff --git a/LearningHub.Nhs.WebUI/Helpers/OpenApiFacade.cs b/LearningHub.Nhs.WebUI/Helpers/OpenApiFacade.cs new file mode 100644 index 000000000..32c529a0d --- /dev/null +++ b/LearningHub.Nhs.WebUI/Helpers/OpenApiFacade.cs @@ -0,0 +1,241 @@ +namespace LearningHub.Nhs.WebUI.Helpers +{ + using System; + using System.Net.Http; + using System.Text; + using System.Threading.Tasks; + using LearningHub.Nhs.Models.Common; + using LearningHub.Nhs.WebUI.Interfaces; + using Newtonsoft.Json; + + /// + /// Defines the . + /// + public class OpenApiFacade : IOpenApiFacade + { + /// + /// Defines the _client. + /// + private readonly IOpenApiHttpClient client; + + /// + /// Initializes a new instance of the class. + /// + /// The client. + public OpenApiFacade(IOpenApiHttpClient client) + { + this.client = client; + } + + /// + /// The GetAsync. + /// + /// . + /// The url. + /// The . + public async Task GetAsync(string url) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var vm = new T(); + + var response = await client.GetAsync(url).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + vm = JsonConvert.DeserializeObject(result); + + return vm; + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PostAsync. + /// + /// . + /// The url. + /// The body. + /// The . + public async Task PostAsync(string url, T body) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PostAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + return; + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("AccessDenied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PostAsync. + /// + /// The return type. + /// The type of body parameter. + /// The url. + /// The body. + /// The . + public async Task PostAsync(string url, TBody body) + where TBody : class, new() + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var vm = new T(); + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PostAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PostAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PutAsync. + /// + /// The url. + /// The . + public async Task PutAsync(string url) + { + var client = await this.client.GetClientAsync(); + + var response = await client.PutAsync(url, null).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PutAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + + /// + /// The PutAsync. + /// + /// . + /// The url. + /// The body. + /// The . + public async Task PutAsync(string url, T body) + where T : class, new() + { + var client = await this.client.GetClientAsync(); + + var content = new StringContent(JsonConvert.SerializeObject(body), Encoding.UTF8, "application/json"); + var response = await client.PutAsync(url, content).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var result = response.Content.ReadAsStringAsync().Result; + var apiResponse = JsonConvert.DeserializeObject(result); + if (apiResponse.Success) + { + return apiResponse; + } + else + { + string details = string.Empty; + if (apiResponse.ValidationResult != null) + { + if (apiResponse.ValidationResult.Details != null) + { + details = $"::ValidationResult: {string.Join(",", apiResponse.ValidationResult.Details)}"; + } + } + + throw new Exception($"PutAsync ApiResponse returned False: {details}"); + } + } + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized + || + response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + throw new Exception("Access Denied"); + } + else + { + throw new Exception($"Exception HttpStatusCode={response.StatusCode}"); + } + } + } +} diff --git a/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs b/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs new file mode 100644 index 000000000..e0601d156 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs @@ -0,0 +1,82 @@ +namespace LearningHub.Nhs.WebUI.Helpers; + +/// +/// Represents the types of resources available in Moodle. +/// +public enum ResourceTypeEnumMoodle +{ + /// + /// The undefined resource type. + /// + Undefined, + + /// + /// The article resource type. + /// + Article, + + /// + /// The audio resource type. + /// + Audio, + + /// + /// The embedded resource type. + /// + Embedded, + + /// + /// The equipment resource type. + /// + Equipment, + + /// + /// The image resource type. + /// + Image, + + /// + /// The SCORM resource type. + /// + Scorm, + + /// + /// The video resource type. + /// + Video, + + /// + /// The web link resource type. + /// + WebLink, + + /// + /// The generic file resource type. + /// + GenericFile, + + /// + /// The clinical case resource type. + /// + Case, + + /// + /// The assessment resource type. + /// + Assessment, + + /// + /// The HTML resource type. + /// + Html, + + /// + /// The Moodle resource type. + /// + Moodle, + + /// + /// The Moodle course resource type. + /// + Course, +} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs index 03e93fc07..ef71191f9 100644 --- a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs @@ -32,6 +32,25 @@ 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", ResourceTypeEnumMoodle.Video }, + { "article", ResourceTypeEnumMoodle.Article }, + { "case", ResourceTypeEnumMoodle.Case }, + { "weblink", ResourceTypeEnumMoodle.WebLink }, + { "audio", ResourceTypeEnumMoodle.Audio }, + { "scorm", ResourceTypeEnumMoodle.Scorm }, + { "assessment", ResourceTypeEnumMoodle.Assessment }, + { "genericfile", ResourceTypeEnumMoodle.GenericFile }, + { "image", ResourceTypeEnumMoodle.Image }, + { "html", ResourceTypeEnumMoodle.Html }, + { "moodle", ResourceTypeEnumMoodle.Course }, + }; + /// /// The FormatTwitterDate. /// @@ -147,6 +166,54 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType } } + /// 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(ResourceTypeEnumMoodle resourceType, int? durationInMilliseconds = 0) + { + switch (resourceType) + { + case ResourceTypeEnumMoodle.Assessment: + return "Assessment"; + case ResourceTypeEnumMoodle.Article: + return "Article"; + case ResourceTypeEnumMoodle.Audio: + string durationText = GetDurationText(durationInMilliseconds ?? 0); + durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; + return "Audio" + durationText; + case ResourceTypeEnumMoodle.Equipment: + return "Equipment"; + case ResourceTypeEnumMoodle.Image: + return "Image"; + case ResourceTypeEnumMoodle.Scorm: + return "elearning"; + case ResourceTypeEnumMoodle.Video: + durationText = GetDurationText(durationInMilliseconds ?? 0); + durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; + return "Video" + durationText; + case ResourceTypeEnumMoodle.WebLink: + return "Web link"; + case ResourceTypeEnumMoodle.GenericFile: + return "File"; + case ResourceTypeEnumMoodle.Embedded: + return "Embedded"; + case ResourceTypeEnumMoodle.Case: + return "Case"; + case ResourceTypeEnumMoodle.Html: + return "HTML"; + case ResourceTypeEnumMoodle.Moodle: + return "Course"; + case ResourceTypeEnumMoodle.Course: + return "Course"; + default: + return "File"; + } + } + /// /// Returns a prettified resource type name, suitable for display in the UI. Excludes video/audio duration string. /// diff --git a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs index 8d17307cf..f3bd9259c 100644 --- a/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/ViewActivityHelper.cs @@ -84,7 +84,15 @@ public static string GetResourceTypeVerb(this ActivityDetailedItemViewModel acti case ResourceTypeEnum.Article: return "Read"; case ResourceTypeEnum.Audio: - return "Played " + GetDurationText(activityDetailedItemViewModel.ActivityDurationSeconds * 1000); + if ((activityDetailedItemViewModel.ActivityDurationSeconds * 1000) > activityDetailedItemViewModel.ResourceDurationMilliseconds) + { + return "Played " + GetDurationText(activityDetailedItemViewModel.ResourceDurationMilliseconds); + } + else + { + return "Played " + GetDurationText(activityDetailedItemViewModel.ActivityDurationSeconds * 1000); + } + case ResourceTypeEnum.Embedded: return string.Empty; case ResourceTypeEnum.Equipment: @@ -112,7 +120,15 @@ public static string GetResourceTypeVerb(this ActivityDetailedItemViewModel acti } case ResourceTypeEnum.Video: - return "Played " + GetDurationText(activityDetailedItemViewModel.ActivityDurationSeconds * 1000); + if ((activityDetailedItemViewModel.ActivityDurationSeconds * 1000) > activityDetailedItemViewModel.ResourceDurationMilliseconds) + { + return "Played " + GetDurationText(activityDetailedItemViewModel.ResourceDurationMilliseconds); + } + else + { + return "Played " + GetDurationText(activityDetailedItemViewModel.ActivityDurationSeconds * 1000); + } + case ResourceTypeEnum.WebLink: return "Visited"; case ResourceTypeEnum.Html: diff --git a/LearningHub.Nhs.WebUI/Interfaces/IOpenApiHttpClient.cs b/LearningHub.Nhs.WebUI/Interfaces/IOpenApiHttpClient.cs new file mode 100644 index 000000000..4c53a2c38 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Interfaces/IOpenApiHttpClient.cs @@ -0,0 +1,17 @@ +namespace LearningHub.Nhs.WebUI.Interfaces +{ + using System.Net.Http; + using System.Threading.Tasks; + + /// + /// The OpenApiHttpClient interface. + /// + public interface IOpenApiHttpClient + { + /// + /// The get client. + /// + /// The . + Task GetClientAsync(); + } +} diff --git a/LearningHub.Nhs.WebUI/Interfaces/IUserGroupService.cs b/LearningHub.Nhs.WebUI/Interfaces/IUserGroupService.cs index a333e0c89..eadae3363 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IUserGroupService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IUserGroupService.cs @@ -22,6 +22,12 @@ public interface IUserGroupService /// The . Task> GetRoleUserGroupDetailForUserAsync(int userId); + /// + /// The UserHasCatalogueContributionPermission. + /// + /// The . + Task UserHasCatalogueContributionPermission(); + /// /// Check if user has given permission. /// diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs index ad94f7b7a..b214cf072 100644 --- a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs @@ -92,10 +92,15 @@ public class MoodleCourseResponseViewModel /// public int? Category { get; set; } + /// + /// Gets the progress percentage formatted as a string. + /// + public string ProgressPercentage => $"{System.Math.Round(this.Progress ?? 0)}%"; + /// /// Gets or sets the progress. /// - public int? Progress { get; set; } + public double? Progress { get; set; } /// /// Gets or sets the completion status. diff --git a/LearningHub.Nhs.WebUI/Models/UserProfile/UserGradeUpdateViewModel.cs b/LearningHub.Nhs.WebUI/Models/UserProfile/UserGradeUpdateViewModel.cs index af9915c18..5394cf09b 100644 --- a/LearningHub.Nhs.WebUI/Models/UserProfile/UserGradeUpdateViewModel.cs +++ b/LearningHub.Nhs.WebUI/Models/UserProfile/UserGradeUpdateViewModel.cs @@ -38,7 +38,7 @@ public class UserGradeUpdateViewModel /// /// Gets or sets the selected grade id. /// - public int? SelectedGradeId { get; set; } + public string SelectedGradeId { get; set; } /// /// Gets or sets the grade list. diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/Contribute.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/Contribute.vue index f25aa0b7f..56c01dce8 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/Contribute.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/Contribute.vue @@ -432,7 +432,7 @@ return this.resourceDetails.resourceLicenceId > 0; }, locationTabComplete(): boolean { - return this.resourceDetails.resourceCatalogueId > 0; + return this.resourceDetails.resourceCatalogueId > 1; }, certificateTabComplete(): boolean { return this.resourceDetails.certificateEnabled !== null; diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeAssessmentSettings.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeAssessmentSettings.vue index 088f74c90..bc7de0277 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeAssessmentSettings.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeAssessmentSettings.vue @@ -74,9 +74,7 @@ + :initialValue="endGuidance"/>

Tip

diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeLocationTab.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeLocationTab.vue index a66944a40..8af5f25c9 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeLocationTab.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute-resource/ContributeLocationTab.vue @@ -7,33 +7,57 @@

Primary catalogue

- +
- -
- + + + + +
+ +
+ +
+ + +
- \ No newline at end of file + diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/CatalogueSelect.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/CatalogueSelect.vue index 379e9572a..8754e4e0c 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/CatalogueSelect.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/CatalogueSelect.vue @@ -26,8 +26,7 @@ A catalogue is a curated set of resources that has its own web page.

- You can contribute a resource as an editor of a catalogue or in your own name. - To contribute a resource in your own name, select Community contributions from the drop down menu. + You can contribute a resource as an editor of a catalogue.

You can manage all resources that you have contributed in the My contributions area. @@ -46,9 +45,11 @@ -

- You have selected a hidden catalogue. - If you publish this resource, learners will only be able to access it when the catalogue is made available by Learning Hub platform administrators. +
+
+ You have selected a hidden catalogue. + If you publish this resource, learners will only be able to access it when the catalogue is made available by Learning Hub platform administrators. +
@@ -88,9 +89,12 @@ }, }, created() { - if (this.value > 0) { + if (this.value > 1) { this.selectedCatalogue = this.userCatalogues.find(c => c.nodeId == this.value); } + else { + this.selectedCatalogue = new CatalogueModel({ nodeId: 0 }); + } } }) diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/ContentCommon.vue b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/ContentCommon.vue index 338817b8b..f62b7d784 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/ContentCommon.vue +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/ContentCommon.vue @@ -83,7 +83,7 @@
-

+

@@ -333,8 +333,9 @@ return this.$store.state.resourceDetail.resourceType; }, showCatalogueSelect(): boolean { - return (this.resourceDetail.resourceCatalogueId === this.resourceDetail.nodeId) || // show if user is contributing into the catalogue root - !Boolean(this.$route.query.initialCreate); // or if the user is editing an existing draft (initialCreate=false) + //return (this.resourceDetail.resourceCatalogueId === this.resourceDetail.nodeId) || // show if user is contributing into the catalogue root + // !Boolean(this.$route.query.initialCreate); // or if the user is editing an existing draft (initialCreate=false) + return (!Boolean(this.$route.query.initialCreate)); }, newKeywordTrimmed(): string { return this.newKeyword?.trim().replace(/ +(?= )/g, ''); diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts index e4bdf763a..0ccb4ce69 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/contribute/contributeState.ts @@ -114,7 +114,7 @@ const setCommonContentState = function (state: State) { && state.resourceDetail.resourceAccessibilityEnum !== ResourceAccessibility.None && state.resourceDetail.description !== '' && (state.resourceDetail.resourceLicenceId > 0 || state.resourceDetail.resourceType === ResourceType.WEBLINK) - && state.resourceDetail.resourceCatalogueId > 0 + && state.resourceDetail.resourceCatalogueId > 1 && state.resourceDetail.resourceAuthors.length > 0 && state.resourceDetail.certificateEnabled !== null && state.resourceDetail.resourceKeywords.length > 0; diff --git a/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/user.ts b/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/user.ts index 9f50357fc..e38fd4a08 100644 --- a/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/user.ts +++ b/LearningHub.Nhs.WebUI/Scripts/vuesrc/data/user.ts @@ -67,15 +67,15 @@ const IsSystemAdmin = async function (): Promise { }; const IsValidUser = async function (currentPassword: string): Promise { - var IsValidUser = `/api/User/ConfirmPassword/${currentPassword}`; - return await AxiosWrapper.axios.get(IsValidUser) - .then(response => { - return response.data; - }) - .catch(e => { - console.log('IsValidUser:' + e); - throw e; + try { + const response = await AxiosWrapper.axios.post('/api/User/ConfirmPassword', { + PasswordHash: currentPassword }); + return response.data; + } catch (e) { + console.error('IsValidUser:', e); + throw e; + } }; const getCurrentUserBasicDetails = async function (): Promise { diff --git a/LearningHub.Nhs.WebUI/Services/ActivityService.cs b/LearningHub.Nhs.WebUI/Services/ActivityService.cs index a494bea91..185dc3a2c 100644 --- a/LearningHub.Nhs.WebUI/Services/ActivityService.cs +++ b/LearningHub.Nhs.WebUI/Services/ActivityService.cs @@ -21,9 +21,10 @@ public class ActivityService : BaseService, IActivityService /// Initializes a new instance of the class. ///
/// Learning hub http client. + /// OpenApiHttpClient http client. /// Logger. - public ActivityService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public ActivityService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } diff --git a/LearningHub.Nhs.WebUI/Services/AzureMediaService.cs b/LearningHub.Nhs.WebUI/Services/AzureMediaService.cs index 6068bc067..f2877b9eb 100644 --- a/LearningHub.Nhs.WebUI/Services/AzureMediaService.cs +++ b/LearningHub.Nhs.WebUI/Services/AzureMediaService.cs @@ -71,7 +71,7 @@ public async Task CreateMediaInputAsset(IFormFile file) string filename = Regex.Replace(file.FileName, "[^a-zA-Z0-9.]", string.Empty); var destContainer = new BlobContainerClient(new Uri(uploadSasUrl)); - var destBlob = destContainer.GetBlockBlobClient(filename.IsNullOrEmpty() ? "file.txt" : filename); + var destBlob = destContainer.GetBlockBlobClient(string.IsNullOrEmpty(filename) ? "file.txt" : filename); await destBlob.UploadAsync(file.OpenReadStream()); return asset.Name; diff --git a/LearningHub.Nhs.WebUI/Services/BaseService.cs b/LearningHub.Nhs.WebUI/Services/BaseService.cs index 87d4cfc79..ddcbad86f 100644 --- a/LearningHub.Nhs.WebUI/Services/BaseService.cs +++ b/LearningHub.Nhs.WebUI/Services/BaseService.cs @@ -11,6 +11,7 @@ public abstract class BaseService { private readonly ILogger logger; private readonly ILearningHubHttpClient learningHubHttpClient; + private readonly IOpenApiHttpClient openApiHttpClient; /// /// Initializes a new instance of the class. @@ -23,11 +24,29 @@ protected BaseService(ILearningHubHttpClient learningHubHttpClient, ILogger l this.logger = logger; } + /// + /// Initializes a new instance of the class. + /// + /// The learningHubHttpClient. + /// The openApiHttpClient. + /// The logger. + protected BaseService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + { + this.learningHubHttpClient = learningHubHttpClient; + this.openApiHttpClient = openApiHttpClient; + this.logger = logger; + } + /// /// Gets the LearningHubHttpClient. /// protected ILearningHubHttpClient LearningHubHttpClient => this.learningHubHttpClient; + /// + /// Gets the OpenApiHttpClient. + /// + protected IOpenApiHttpClient OpenApiHttpClient => this.openApiHttpClient; + /// /// Gets the Logger. /// diff --git a/LearningHub.Nhs.WebUI/Services/BoomarkService.cs b/LearningHub.Nhs.WebUI/Services/BoomarkService.cs index 5a26148cc..15d5509f9 100644 --- a/LearningHub.Nhs.WebUI/Services/BoomarkService.cs +++ b/LearningHub.Nhs.WebUI/Services/BoomarkService.cs @@ -19,16 +19,17 @@ public class BoomarkService : BaseService, IBookmarkService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The openApiHttpClient. /// The logger. - public BoomarkService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public BoomarkService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } /// public async Task Create(UserBookmarkViewModel bookmarkViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "bookmark/Create"; var content = new StringContent( JsonConvert.SerializeObject(bookmarkViewModel), @@ -56,7 +57,7 @@ public async Task Create(UserBookmarkViewModel bookmarkViewModel) /// public async Task Edit(UserBookmarkViewModel bookmarkViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "bookmark/Edit"; var content = new StringContent( JsonConvert.SerializeObject(bookmarkViewModel), @@ -84,7 +85,7 @@ public async Task Edit(UserBookmarkViewModel bookmarkViewModel) /// public async Task DeleteFolder(int bookmarkId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"bookmark/deletefolder/{bookmarkId}"; var response = await client.DeleteAsync(request).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized @@ -98,7 +99,7 @@ public async Task DeleteFolder(int bookmarkId) /// public async Task> GetAllByParent(int? parentId, bool? all = false) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"bookmark/GetAllByParent/{parentId}?all={all}"; var response = await client.GetAsync(request).ConfigureAwait(false); if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized @@ -120,7 +121,7 @@ public async Task> GetAllByParent(int? parent /// public async Task Toggle(UserBookmarkViewModel bookmarkViewModel) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "bookmark/toggle"; var content = new StringContent( JsonConvert.SerializeObject(bookmarkViewModel), diff --git a/LearningHub.Nhs.WebUI/Services/CardService.cs b/LearningHub.Nhs.WebUI/Services/CardService.cs index d0795c0ad..d3aac0616 100644 --- a/LearningHub.Nhs.WebUI/Services/CardService.cs +++ b/LearningHub.Nhs.WebUI/Services/CardService.cs @@ -19,9 +19,10 @@ public class CardService : BaseService, ICardService /// Initializes a new instance of the class. ///
/// The Learning Hub Http Client. + /// The Open Api Http Client. /// The logger. - public CardService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public CardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } @@ -34,7 +35,7 @@ public async Task GetMyContributionsTotalsAsync( { MyContributionsTotalsViewModel totals = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetMyContributionsTotals/{catalogueId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -63,7 +64,7 @@ public async Task> GetContributionsAsync( { List myContributionCards = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(resourceContributionsRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -94,7 +95,7 @@ public async Task GetMyResourceViewModelAsync() { MyResourceViewModel myresourcecards = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetMyResourceViewModel"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -123,7 +124,7 @@ public async Task GetResourceCardExtendedViewMode { ResourceCardExtendedViewModel resourceCardExtendedViewModel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/ResourceCardExtendedViewModel/{id.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/CatalogueService.cs b/LearningHub.Nhs.WebUI/Services/CatalogueService.cs index a8a6d3055..3833a4e28 100644 --- a/LearningHub.Nhs.WebUI/Services/CatalogueService.cs +++ b/LearningHub.Nhs.WebUI/Services/CatalogueService.cs @@ -25,10 +25,11 @@ public class CatalogueService : BaseService, ICatalogueService /// Initializes a new instance of the class. ///
/// The learning hub http client. + /// The Open Api Http Client. /// The logger. /// The cacheService. - public CatalogueService(ILearningHubHttpClient learningHubHttpClient, ILogger logger, ICacheService cacheService) - : base(learningHubHttpClient, logger) + public CatalogueService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, ICacheService cacheService) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.cacheService = cacheService; } @@ -41,7 +42,7 @@ public async Task> GetCataloguesForUserAsync() { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Catalogue/GetForCurrentUser"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -70,7 +71,7 @@ public async Task GetCatalogueAsync(string reference) { CatalogueViewModel viewmodel = new CatalogueViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"catalogue/catalogue/{reference}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -98,7 +99,7 @@ public async Task GetCatalogueAsync(int catalogueNodeVersion { CatalogueViewModel viewmodel = new CatalogueViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"catalogue/catalogues/{catalogueNodeVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -126,7 +127,7 @@ public async Task GetCatalogueRecordedAsync(string reference { CatalogueViewModel viewmodel = new CatalogueViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"catalogue/catalogue-recorded/{reference}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -154,7 +155,7 @@ public async Task GetResourcesAsync(Catalogu { CatalogueResourceResponseViewModel viewmodel = new CatalogueResourceResponseViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(requestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -185,7 +186,7 @@ public async Task CanCurrentUserEditCatalogue(int catalogueId) { var request = $"Catalogue/CanCurrentUserEditCatalogue/{catalogueId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync(request).ConfigureAwait(false); var catalogueIsEditable = false; @@ -213,7 +214,7 @@ public async Task AccessDetailsAsync(string ref { var request = $"Catalogue/AccessDetails/{reference}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync(request).ConfigureAwait(false); var accessDetails = new CatalogueAccessDetailsViewModel(); @@ -241,7 +242,7 @@ public async Task GetLatestCatalogueAccessReque { var request = $"Catalogue/GetLatestCatalogueAccessRequest/{catalogueNodeId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync(request).ConfigureAwait(false); var car = new CatalogueAccessRequestViewModel(); @@ -275,7 +276,7 @@ public async Task RequestAccessAsync(string referen { var request = $"Catalogue/RequestAccess/{reference}/{accessType}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(vm), Encoding.UTF8, "application/json"); var response = await client.PostAsync(request, content).ConfigureAwait(false); var catalogueAccessRequested = false; @@ -308,7 +309,7 @@ public async Task InviteUserAsync(RestrictedCatalog { var request = $"Catalogue/InviteUser"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(vm), Encoding.UTF8, "application/json"); var response = await client.PostAsync(request, content).ConfigureAwait(false); var catalogueAccessRequested = false; @@ -344,7 +345,7 @@ public async Task> GetRestricted var json = JsonConvert.SerializeObject(requestModel); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Catalogue/GetRestrictedCatalogueAccessRequests"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -377,7 +378,7 @@ public async Task GetRestrictedCatalogueSum { var viewmodel = new RestrictedCatalogueSummaryViewModel(); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"catalogue/GetRestrictedCatalogueSummary/{catalogueNodeId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -412,7 +413,7 @@ public async Task GetRestrictedCatalogueUsers var json = JsonConvert.SerializeObject(requestModel); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Catalogue/GetRestrictedCatalogueUsers"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -446,7 +447,7 @@ public async Task AcceptAccessRequestAsync(int acce { var request = $"Catalogue/AcceptAccessRequest/{accessRequestId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(new { })); var response = await client.PostAsync(request, content).ConfigureAwait(false); var catalogueAccessRequested = new LearningHubValidationResult(); @@ -478,7 +479,7 @@ public async Task RejectAccessRequestAsync(int acce { var request = $"Catalogue/RejectAccessRequest/{accessRequestId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(new CatalogueAccessRejectionViewModel { RejectionReason = rejectionReason }), Encoding.UTF8, "application/json"); var response = await client.PostAsync(request, content).ConfigureAwait(false); var vr = new LearningHubValidationResult(); @@ -507,7 +508,7 @@ public async Task DismissAccessRequestAsync(int cat { var request = $"Catalogue/DismissAccessRequest/{catalogueNodeId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(new { })); var response = await client.PostAsync(request, content).ConfigureAwait(false); var vr = new LearningHubValidationResult(false); @@ -536,7 +537,7 @@ public async Task GetCatalogueAccessRequestAsyn { var request = $"Catalogue/AccessRequest/{catalogueAccessRequestId}"; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync(request).ConfigureAwait(false); var catalogueAccessRequest = new CatalogueAccessRequestViewModel(); @@ -570,7 +571,7 @@ public async Task RemoveUserFromRestrictedAccessUse var json = JsonConvert.SerializeObject(userGroup); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/DeleteUserUserGroup"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -611,7 +612,7 @@ public async Task RemoveUserFromRestrictedAccessUse public async Task GetAllCatalogueAsync(string filterChar) { AllCatalogueResponseViewModel viewmodel = new AllCatalogueResponseViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"catalogue/allcatalogues/{filterChar}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/ContentService.cs b/LearningHub.Nhs.WebUI/Services/ContentService.cs index 92fe7a7dd..b6d1f9296 100644 --- a/LearningHub.Nhs.WebUI/Services/ContentService.cs +++ b/LearningHub.Nhs.WebUI/Services/ContentService.cs @@ -18,10 +18,11 @@ public class ContentService : BaseService, IContentService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. /// azureMediaService. - public ContentService(ILearningHubHttpClient learningHubHttpClient, ILogger logger, IAzureMediaService azureMediaService) - : base(learningHubHttpClient, logger) + public ContentService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IAzureMediaService azureMediaService) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.azureMediaService = azureMediaService; } @@ -36,7 +37,7 @@ public async Task GetPageByIdAsync(int id, bool preview) { PageViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync($"content/page/{id}?publishedOnly={!preview}&preview={preview}").ConfigureAwait(false); @@ -63,7 +64,7 @@ public async Task GetPageSectionDetailVideoAssetById { PageSectionDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync($"content/page-section-detail-video/{id}").ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/ContributeService.cs b/LearningHub.Nhs.WebUI/Services/ContributeService.cs index a61487e4e..68a2b4cf6 100644 --- a/LearningHub.Nhs.WebUI/Services/ContributeService.cs +++ b/LearningHub.Nhs.WebUI/Services/ContributeService.cs @@ -39,9 +39,10 @@ public class ContributeService : BaseService, IContributeServ /// Azure media service. /// MKIO media service. /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public ContributeService(IFileService fileService, IResourceService resourceService, IAzureMediaService azureMediaService, ILearningHubHttpClient learningHubHttpClient, ILogger logger, IAzureMediaService mediaService) - : base(learningHubHttpClient, logger) + public ContributeService(IFileService fileService, IResourceService resourceService, IAzureMediaService azureMediaService, ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IAzureMediaService mediaService) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.fileService = fileService; this.resourceService = resourceService; @@ -62,7 +63,7 @@ public async Task CreateNewResourceVersionAsync(int var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/CreateNewResourceVersion"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -96,7 +97,7 @@ public async Task CreateResourceAuthorAsync(ResourceAuthorViewModel resourc var json = JsonConvert.SerializeObject(resourceAuthorViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/AddResourceVersionAuthor"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -130,7 +131,7 @@ public async Task CreateResourceKeywordAsync(ResourceKeywordViewModel resou var json = JsonConvert.SerializeObject(resourceKeywordViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/AddResourceVersionKeyword"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -163,7 +164,7 @@ public async Task DeleteArticleFileAsync(FileDeleteRequestModel model) var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteArticleFile"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -193,7 +194,7 @@ public async Task DeleteArticleFileAsync(FileDeleteRequestModel model) /// The . public async Task DeleteFileChunkDetailAsync(int fileChunkDetailId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteFileChunkDetail/{fileChunkDetailId}"; var response = await client.DeleteAsync(request).ConfigureAwait(false); @@ -224,7 +225,7 @@ public async Task DeleteResourceAttributeFileAsync(FileDeleteRequestModel var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteResourceAttributeFile"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -257,7 +258,7 @@ public async Task DeleteResourceAuthorAsync(AuthorDeleteRequestModel model var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteResourceVersionAuthor"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -290,7 +291,7 @@ public async Task DeleteResourceKeywordAsync(KeywordDeleteRequestModel mod var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteResourceVersionKeyword"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -320,7 +321,7 @@ public async Task DeleteResourceKeywordAsync(KeywordDeleteRequestModel mod /// The . public async Task DeleteResourceVersionAsync(int resourceVersionId) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteResourceVersion/{resourceVersionId}"; var response = await client.DeleteAsync(request).ConfigureAwait(false); @@ -356,7 +357,7 @@ public async Task GetFileChunkDetail(int fileChunkDeta { FileChunkDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetFileChunkDetail/{fileChunkDetailId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -799,7 +800,7 @@ public async Task SaveArticleAttachedFileDetailsAsync(FileCreateRequestView var json = JsonConvert.SerializeObject(fileCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SaveArticleAttachedFileDetails"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -833,7 +834,7 @@ public async Task SaveArticleDetailAsync(ArticleUpdateRequestViewModel arti var json = JsonConvert.SerializeObject(articleViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateArticleDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -867,7 +868,7 @@ public async Task SaveFileChunkDetailsAsync(FileChunkDetailViewModel fileCh var json = JsonConvert.SerializeObject(fileChunkDetailCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SaveFileChunkDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -901,7 +902,7 @@ public async Task SaveFileDetailsAsync(FileCreateRequestViewModel fileCreat var json = JsonConvert.SerializeObject(fileCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SaveFileDetails"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -935,7 +936,7 @@ public async Task SaveGenericFileDetailAsync(GenericFileUpdateRequestViewMo var json = JsonConvert.SerializeObject(genericFileViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateGenericFileDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -969,7 +970,7 @@ public async Task SaveScormDetailAsync(ScormUpdateRequestViewModel scormUpd var json = JsonConvert.SerializeObject(scormUpdateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateScormDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1003,7 +1004,7 @@ public async Task SaveHtmlDetailAsync(HtmlResourceUpdateRequestViewModel ht var json = JsonConvert.SerializeObject(htmlResource); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateHtmlDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1037,7 +1038,7 @@ public async Task SaveImageDetailAsync(ImageUpdateRequestViewModel imageVie var json = JsonConvert.SerializeObject(imageViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateImageDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1071,7 +1072,7 @@ public async Task SaveResourceAttributeFileDetailsAsync(FileCreateRequestVi var json = JsonConvert.SerializeObject(fileCreateRequestViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SaveResourceAttributeFileDetails"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1128,7 +1129,7 @@ public async Task SaveWeblinkDetailAsync(WebLinkViewModel weblinkViewModel) var json = JsonConvert.SerializeObject(weblinkViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateWeblinkDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1162,7 +1163,7 @@ public async Task SaveCaseDetailAsync(CaseViewModel caseViewModel) var json = JsonConvert.SerializeObject(caseViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateCaseDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1196,7 +1197,7 @@ public async Task SaveAssessmentDetailAsync(AssessmentViewModel assessmentV var json = JsonConvert.SerializeObject(assessmentViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateAssessmentDetail"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1230,7 +1231,7 @@ public async Task SubmitResourceVersionForPublishAs var json = JsonConvert.SerializeObject(publishViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/SubmitResourceVersionForPublish"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1335,7 +1336,7 @@ private async Task CreateResourceAsync(ResourceDetailViewModel resourceDeta var json = JsonConvert.SerializeObject(resourceDetailViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/CreateResource"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1368,7 +1369,7 @@ private async Task UpdateResourceVersionAsync(ResourceDetailViewModel resourceDe var json = JsonConvert.SerializeObject(resourceDetailViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UpdateResourceVersion"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/CountryService.cs b/LearningHub.Nhs.WebUI/Services/CountryService.cs index 2c0c7e120..e1afd4b35 100644 --- a/LearningHub.Nhs.WebUI/Services/CountryService.cs +++ b/LearningHub.Nhs.WebUI/Services/CountryService.cs @@ -20,13 +20,15 @@ public class CountryService : BaseService, ICountryService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public CountryService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/DashboardService.cs b/LearningHub.Nhs.WebUI/Services/DashboardService.cs index 55f5153bf..607d4f2be 100644 --- a/LearningHub.Nhs.WebUI/Services/DashboardService.cs +++ b/LearningHub.Nhs.WebUI/Services/DashboardService.cs @@ -26,10 +26,11 @@ public class DashboardService : BaseService, IDashboardService /// Initializes a new instance of the class. /// /// learningHubHttpClient. + /// The Open Api Http Client. /// logger. /// MoodleHttpClient. - public DashboardService(ILearningHubHttpClient learningHubHttpClient, ILogger logger, IMoodleHttpClient moodleHttpClient) - : base(learningHubHttpClient, logger) + public DashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IMoodleHttpClient moodleHttpClient) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.moodleHttpClient = moodleHttpClient; } @@ -44,7 +45,7 @@ public async Task GetMyAccessLearningsAsyn { DashboardMyLearningResponseViewModel viewmodel = new DashboardMyLearningResponseViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"dashboard/myaccesslearning/{dashboardType}/{pageNumber}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -73,7 +74,7 @@ public async Task GetCataloguesAsync(string { DashboardCatalogueResponseViewModel viewmodel = new DashboardCatalogueResponseViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"dashboard/catalogues/{dashboardType}/{pageNumber}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -102,7 +103,7 @@ public async Task GetResourcesAsync(string d { DashboardResourceResponseViewModel viewmodel = new DashboardResourceResponseViewModel { }; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"dashboard/resources/{dashboardType}/{pageNumber}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -149,7 +150,7 @@ public async Task RecordDashBoardEventAsync(DashboardEventViewModel dashboardEve }; var content = new System.Net.Http.StringContent(JsonConvert.SerializeObject(eventEntity), Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"event/Create"; var response = await client.PostAsync(request, content).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/DetectJsLogService.cs b/LearningHub.Nhs.WebUI/Services/DetectJsLogService.cs index da62c5cbd..e9bf607ce 100644 --- a/LearningHub.Nhs.WebUI/Services/DetectJsLogService.cs +++ b/LearningHub.Nhs.WebUI/Services/DetectJsLogService.cs @@ -14,9 +14,10 @@ public class DetectJsLogService : BaseService, IDetectJsLogS /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public DetectJsLogService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public DetectJsLogService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } diff --git a/LearningHub.Nhs.WebUI/Services/GradeService.cs b/LearningHub.Nhs.WebUI/Services/GradeService.cs index fb0a42074..37df9b048 100644 --- a/LearningHub.Nhs.WebUI/Services/GradeService.cs +++ b/LearningHub.Nhs.WebUI/Services/GradeService.cs @@ -19,13 +19,15 @@ public class GradeService : BaseService, IGradeService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public GradeService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/HierarchyService.cs b/LearningHub.Nhs.WebUI/Services/HierarchyService.cs index 4bd8f7734..6bed5fd27 100644 --- a/LearningHub.Nhs.WebUI/Services/HierarchyService.cs +++ b/LearningHub.Nhs.WebUI/Services/HierarchyService.cs @@ -16,21 +16,23 @@ public class HierarchyService : BaseService, IHierarchyService /// /// Defines the _facade. /// - private readonly ILearningHubApiFacade facade; + private readonly IOpenApiFacade facade; /// /// Initializes a new instance of the class. /// /// The learning hub http client. - /// The learningHubApiFacade. + /// The Open Api Http Client. + /// The openApiFacade. /// The logger. public HierarchyService( ILearningHubHttpClient learningHubHttpClient, - ILearningHubApiFacade learningHubApiFacade, + IOpenApiHttpClient openApiHttpClient, + IOpenApiFacade openApiFacade, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { - this.facade = learningHubApiFacade; + this.facade = openApiFacade; } /// diff --git a/LearningHub.Nhs.WebUI/Services/InternalSystemService.cs b/LearningHub.Nhs.WebUI/Services/InternalSystemService.cs index d578d9523..bb19a0f38 100644 --- a/LearningHub.Nhs.WebUI/Services/InternalSystemService.cs +++ b/LearningHub.Nhs.WebUI/Services/InternalSystemService.cs @@ -16,9 +16,10 @@ public class InternalSystemService : BaseService, IIntern /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public InternalSystemService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public InternalSystemService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } diff --git a/LearningHub.Nhs.WebUI/Services/JobRoleService.cs b/LearningHub.Nhs.WebUI/Services/JobRoleService.cs index bbf9f4402..766d05e60 100644 --- a/LearningHub.Nhs.WebUI/Services/JobRoleService.cs +++ b/LearningHub.Nhs.WebUI/Services/JobRoleService.cs @@ -22,13 +22,15 @@ public class JobRoleService : BaseService, IJobRoleService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public JobRoleService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/LocationService.cs b/LearningHub.Nhs.WebUI/Services/LocationService.cs index 2ba678ab0..04423a0b6 100644 --- a/LearningHub.Nhs.WebUI/Services/LocationService.cs +++ b/LearningHub.Nhs.WebUI/Services/LocationService.cs @@ -19,13 +19,15 @@ public class LocationService : BaseService, ILocationService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public LocationService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/LoginWizardService.cs b/LearningHub.Nhs.WebUI/Services/LoginWizardService.cs index 306d69304..06fd7e428 100644 --- a/LearningHub.Nhs.WebUI/Services/LoginWizardService.cs +++ b/LearningHub.Nhs.WebUI/Services/LoginWizardService.cs @@ -24,13 +24,15 @@ public class LoginWizardService : BaseService, ILoginWizardS /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public LoginWizardService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/MyLearningService.cs b/LearningHub.Nhs.WebUI/Services/MyLearningService.cs index c6f9f2ffb..1e1662201 100644 --- a/LearningHub.Nhs.WebUI/Services/MyLearningService.cs +++ b/LearningHub.Nhs.WebUI/Services/MyLearningService.cs @@ -20,9 +20,10 @@ public class MyLearningService : BaseService, IMyLearningServ /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The Open Api Http Client. /// The logger. - public MyLearningService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public MyLearningService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } @@ -38,7 +39,7 @@ public async Task GetActivityDetailed(MyLearningReq var json = JsonConvert.SerializeObject(requestModel); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"MyLearning/GetActivityDetailed"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -67,7 +68,7 @@ public async Task GetActivityDetailed(MyLearningReq public async Task> GetPlayedSegments(int resourceId, int majorVersion) { List viewModel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"MyLearning/GetPlayedSegments/{resourceId}/{majorVersion}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -98,7 +99,7 @@ public async Task> GetPlayedSegments(int resourceId public async Task> GetResourceCertificateDetails(int resourceReferenceId, int? majorVersion = 0, int? minorVersion = 0, int? userId = 0) { Tuple viewModel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"MyLearning/GetResourceCertificateDetails/{resourceReferenceId}/{majorVersion}/{minorVersion}/{userId}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/NavigationPermissionService.cs b/LearningHub.Nhs.WebUI/Services/NavigationPermissionService.cs index 95e74022e..e381b0403 100644 --- a/LearningHub.Nhs.WebUI/Services/NavigationPermissionService.cs +++ b/LearningHub.Nhs.WebUI/Services/NavigationPermissionService.cs @@ -11,14 +11,19 @@ public class NavigationPermissionService : INavigationPermissionService { private readonly IResourceService resourceService; + private readonly IUserGroupService userGroupService; /// /// Initializes a new instance of the class. /// /// Resource service. - public NavigationPermissionService(IResourceService resourceService) + /// UserGroup service. + public NavigationPermissionService( + IResourceService resourceService, + IUserGroupService userGroupService) { this.resourceService = resourceService; + this.userGroupService = userGroupService; } /// @@ -52,7 +57,7 @@ public async Task GetNavigationModelAsync(IPrincipal user, bool } else if (user.IsInRole("BlueUser")) { - return this.AuthenticatedBlueUser(controllerName); + return await this.AuthenticatedBlueUser(controllerName); } else { @@ -114,11 +119,11 @@ private NavigationModel AuthenticatedAdministrator(string controllerName) /// /// The controller name. /// The . - private NavigationModel AuthenticatedBlueUser(string controllerName) + private async Task AuthenticatedBlueUser(string controllerName) { return new NavigationModel() { - ShowMyContributions = true, + ShowMyContributions = await this.userGroupService.UserHasCatalogueContributionPermission(), ShowMyLearning = true, ShowMyBookmarks = true, ShowSearch = controllerName != "search" && controllerName != string.Empty, diff --git a/LearningHub.Nhs.WebUI/Services/NotificationService.cs b/LearningHub.Nhs.WebUI/Services/NotificationService.cs index d41ef30d6..e836edcd9 100644 --- a/LearningHub.Nhs.WebUI/Services/NotificationService.cs +++ b/LearningHub.Nhs.WebUI/Services/NotificationService.cs @@ -22,9 +22,10 @@ public class NotificationService : BaseService, INotificati /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public NotificationService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public NotificationService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } @@ -95,7 +96,7 @@ public async Task> GetPagedAsync(Pagin { PagedResultSet viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var content = new StringContent(JsonConvert.SerializeObject(pagingRequestModel), Encoding.UTF8, "application/json"); @@ -124,7 +125,7 @@ public async Task GetUserNotificationIdAsync(int id) { UserNotification viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserNotification/GetById/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -153,7 +154,7 @@ public async Task GetUserNotificationDetailsAsync(int id) { UserNotification viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserNotification/GetByIdAndUserId/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -182,7 +183,7 @@ public async Task GetUserUnreadNotificationCountAsync(int userid) { int count = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserNotification/GetUserUnreadNotificationCount/{userid}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -212,7 +213,7 @@ private async Task PutAsync(UserNotification notification) var json = JsonConvert.SerializeObject(notification); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserNotification/PutAsync"; var response = await client.PutAsync(request, stringContent).ConfigureAwait(false); @@ -245,7 +246,7 @@ private async Task PostAsync(UserNotification notification) var json = JsonConvert.SerializeObject(notification); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserNotification/PostAsync"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/OpenApiHttpClient.cs b/LearningHub.Nhs.WebUI/Services/OpenApiHttpClient.cs new file mode 100644 index 000000000..54c3b7bb2 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Services/OpenApiHttpClient.cs @@ -0,0 +1,41 @@ +namespace LearningHub.Nhs.WebUI.Services +{ + using System.Net.Http; + using LearningHub.Nhs.Caching; + using LearningHub.Nhs.WebUI.Configuration; + using LearningHub.Nhs.WebUI.Interfaces; + using Microsoft.AspNetCore.Http; + using Microsoft.Extensions.Logging; + using Microsoft.Extensions.Options; + + /// + /// The open api http client. + /// + public class OpenApiHttpClient : BaseHttpClient, IOpenApiHttpClient + { + /// + /// Initializes a new instance of the class. + /// + /// The http context accessor. + /// The web settings. + /// The auth config. + /// The http client. + /// The logger. + /// The cache service. + public OpenApiHttpClient( + IHttpContextAccessor httpContextAccessor, + IOptions webSettings, + LearningHubAuthServiceConfig authConfig, + HttpClient client, + ILogger logger, + ICacheService cacheService) + : base(httpContextAccessor, webSettings.Value, authConfig, client, logger, cacheService) + { + } + + /// + /// Gets the open api url. + /// + public override string ApiUrl => this.WebSettings.OpenApiUrl; + } +} diff --git a/LearningHub.Nhs.WebUI/Services/PartialFileUploadService.cs b/LearningHub.Nhs.WebUI/Services/PartialFileUploadService.cs index 7a7a33616..5ef45d685 100644 --- a/LearningHub.Nhs.WebUI/Services/PartialFileUploadService.cs +++ b/LearningHub.Nhs.WebUI/Services/PartialFileUploadService.cs @@ -34,12 +34,14 @@ public class PartialFileUploadService : BaseService, I /// /// The Settings. /// The learning hub http client. + /// The Open Api Http Client. /// The logger. public PartialFileUploadService( IOptions settings, ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.settings = settings.Value; } diff --git a/LearningHub.Nhs.WebUI/Services/ProviderService.cs b/LearningHub.Nhs.WebUI/Services/ProviderService.cs index 44a91495b..ee6119c60 100644 --- a/LearningHub.Nhs.WebUI/Services/ProviderService.cs +++ b/LearningHub.Nhs.WebUI/Services/ProviderService.cs @@ -22,9 +22,10 @@ public class ProviderService : BaseService, IProviderService /// /// The cache service. /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public ProviderService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public ProviderService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.cacheService = cacheService; } @@ -47,7 +48,7 @@ public async Task> GetProvidersForUserAsync(int userId) { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Provider/GetProvidersByUserId/{userId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -76,7 +77,7 @@ public async Task> GetProvidersForResourceAsync(int reso { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Provider/GetProvidersByResource/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -111,7 +112,7 @@ private async Task> GetAllProviders() { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Provider/all"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/RatingService.cs b/LearningHub.Nhs.WebUI/Services/RatingService.cs index f08361096..fa72f4264 100644 --- a/LearningHub.Nhs.WebUI/Services/RatingService.cs +++ b/LearningHub.Nhs.WebUI/Services/RatingService.cs @@ -19,9 +19,10 @@ public class RatingService : BaseService, IRatingService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public RatingService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public RatingService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } diff --git a/LearningHub.Nhs.WebUI/Services/RegionService.cs b/LearningHub.Nhs.WebUI/Services/RegionService.cs index 6a48fcf5d..f05fc22eb 100644 --- a/LearningHub.Nhs.WebUI/Services/RegionService.cs +++ b/LearningHub.Nhs.WebUI/Services/RegionService.cs @@ -19,10 +19,11 @@ public class RegionService : BaseService, IRegionService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Logger. /// User Api http client. - public RegionService(ILearningHubHttpClient learningHubHttpClient, ILogger logger, IUserApiHttpClient userApiHttpClient) - : base(learningHubHttpClient, logger) + public RegionService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IUserApiHttpClient userApiHttpClient) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/ResourceService.cs b/LearningHub.Nhs.WebUI/Services/ResourceService.cs index 02a233ea0..ec8eaee30 100644 --- a/LearningHub.Nhs.WebUI/Services/ResourceService.cs +++ b/LearningHub.Nhs.WebUI/Services/ResourceService.cs @@ -34,11 +34,12 @@ public class ResourceService : BaseService, IResourceService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Azure media services. /// Logger. /// Settings. - public ResourceService(ILearningHubHttpClient learningHubHttpClient, IAzureMediaService azureMediaService, ILogger logger, IOptions settings) - : base(learningHubHttpClient, logger) + public ResourceService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IAzureMediaService azureMediaService, ILogger logger, IOptions settings) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.settings = settings.Value; this.azureMediaService = azureMediaService; @@ -55,7 +56,7 @@ public async Task AcceptSensitiveContentAsync(int r var stringContent = new StringContent(resourceVersionId.ToString(), Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/AcceptSensitiveContent"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -87,7 +88,7 @@ public async Task GetArticleDetailsByIdAsync(int resourceVersi { ArticleViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetArticleDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -116,7 +117,7 @@ public async Task GetAudioDetailsByIdAsync(int resourceVersionId { AudioViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetAudioDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -145,7 +146,7 @@ public async Task GetByIdAsync(int id) { ResourceHeaderViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceHeaderViewModelAsync/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -173,7 +174,7 @@ public async Task> GetFileTypeAsync() { List fileTypeList = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetFileTypes"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -202,7 +203,7 @@ public async Task GetGenericFileDetailsByIdAsync(int resou { GenericFileViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetGenericFileDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -231,7 +232,7 @@ public async Task GetHtmlDetailsByIdAsync(int resourceVer { HtmlResourceViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetHtmlDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -260,7 +261,7 @@ public async Task GetScormDetailsByIdAsync(int resourceVersionId { ScormViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetScormDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -288,7 +289,7 @@ public async Task GetExternalContentDetailsAsyn { ExternalContentDetailsViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetExternalContentDetailsById/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -317,7 +318,7 @@ public async Task RecordExternalReferenceUserAgreementAsync(ExternalRefere var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/RecordExternalReferenceUserAgreement"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -349,7 +350,7 @@ public async Task GetImageDetailsByIdAsync(int resourceVersionId { ImageViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetImageDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -378,7 +379,7 @@ public async Task GetInformationByIdAsync(int id) { ResourceInformationViewModel resourceInfo = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceInformationViewModelAsync/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -407,7 +408,7 @@ public async Task GetItemByIdAsync(int id) { ResourceItemViewModel resourceItem = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceItemViewModelAsync/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -453,7 +454,7 @@ public async Task> GetLicencesAsync() { List licences = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceLicences"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -482,7 +483,7 @@ public async Task GetLocationsByIdAsync(int id) { CatalogueLocationsViewModel resourceLocations = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetCatalogueLocations/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -511,7 +512,7 @@ public async Task GetResourceVersionAsync(int resourceV { ResourceDetailViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersion/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -540,7 +541,7 @@ public async Task GetResourceVersionViewModelAsync(int { ResourceVersionViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionViewModel/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -569,7 +570,7 @@ public async Task GetResourceVersionExtendedAs { ResourceVersionExtendedViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionExtendedViewModel/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -609,7 +610,7 @@ public async Task GetVideoDetailsByIdAsync(int resourceVersionId { VideoViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetVideoDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -648,7 +649,7 @@ public async Task GetWeblinkDetailsByIdAsync(int resourceVersi { WebLinkViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetWeblinkDetails/{resourceVersionId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -677,7 +678,7 @@ public async Task GetCaseDetailsByIdAsync(int resourceVersionId) { CaseViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetCaseDetails/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -706,7 +707,7 @@ public async Task GetAssessmentDetailsByIdAsync(int resourc { AssessmentViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetAssessmentDetails/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -735,7 +736,7 @@ public async Task GetAssessmentContent(int resourceVersionI { AssessmentViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetAssessmentContent/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -764,7 +765,7 @@ public async Task GetAssessmentProgressByResourceVe { AssessmentProgressViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetAssessmentProgress/resource/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -793,7 +794,7 @@ public async Task GetAssessmentProgressByActivity(i { AssessmentProgressViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetAssessmentProgress/activity/{assessmentResourceActivityId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -822,7 +823,7 @@ public async Task> GetFileStatusDetailsAsync(int[] fileIds) { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); string queryString = string.Join("&", fileIds.Select(fileId => $"fileIds={fileId}")); var request = $"Resource/GetFileStatusDetails?{queryString}"; @@ -855,7 +856,7 @@ public async Task UnpublishResourceVersionAsync(int var json = JsonConvert.SerializeObject(rv); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/UnpublishResourceVersion"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -884,7 +885,7 @@ public async Task UnpublishResourceVersionAsync(int /// The . public async Task UserHasPublishedResourcesAsync() { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/HasPublishedResources"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -916,7 +917,7 @@ public async Task DuplicateResourceAsync(DuplicateR var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DuplicateResource"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -963,7 +964,7 @@ public async Task DuplicateBlocksAsync(DuplicateBlo var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DuplicateBlocks"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1007,7 +1008,7 @@ public async Task> GetMyContri { var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.PostAsync("Resource/GetMyContributions", stringContent).ConfigureAwait(false); @@ -1030,7 +1031,7 @@ public async Task> GetMyContri /// The . public async Task> GetAllPublishedResourceAsync() { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var response = await client.GetAsync("Resource/GetAllPublishedResource").ConfigureAwait(false); @@ -1056,7 +1057,7 @@ public async Task GetResourceVersionVa { ResourceVersionValidationResultViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionValidationResult/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1085,7 +1086,7 @@ public async Task GetResourceVersionExtendedVi { ResourceVersionExtendedViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetResourceVersionExtendedViewModel/{resourceVersionId.ToString()}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1116,7 +1117,7 @@ public async Task RevertToDraft(int resourceVersion var json = JsonConvert.SerializeObject(new { resourceVersionId }); var stringContent = new StringContent(resourceVersionId.ToString(), Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/RevertToDraft"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1160,7 +1161,7 @@ public async Task CreateResourceVersionProviderAsyn var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/AddResourceProvider"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1206,7 +1207,7 @@ public async Task CreateResourceVersionValidationResultAsync(ResourceVersionVali var json = JsonConvert.SerializeObject(validationResultViewModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/CreateResourceVersionValidationResult"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1237,7 +1238,7 @@ public async Task DeleteResourceVersionProviderAsyn var json = JsonConvert.SerializeObject(model); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteResourceProvider"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1278,7 +1279,7 @@ public async Task DeleteResourceVersionProviderAsyn public async Task DeleteAllResourceVersionProviderAsync(int resourceVersionId) { var content = new StringContent(JsonConvert.SerializeObject(new { })); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/DeleteAllResourceProvider/{resourceVersionId}"; var response = await client.PostAsync(request, content).ConfigureAwait(false); @@ -1320,7 +1321,7 @@ public async Task> GetObsoleteResourceFile(int resourceVersionId, b { List filePaths = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Resource/GetObsoleteResourceFile/{resourceVersionId}/{deletedResource}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/RoadMapService.cs b/LearningHub.Nhs.WebUI/Services/RoadMapService.cs index 210a06096..e63f9b9c1 100644 --- a/LearningHub.Nhs.WebUI/Services/RoadMapService.cs +++ b/LearningHub.Nhs.WebUI/Services/RoadMapService.cs @@ -16,9 +16,10 @@ public class RoadMapService : BaseService, IRoadMapService /// Initializes a new instance of the class. /// /// Learing hub http client. + /// The Open Api Http Client. /// Logger. - public RoadMapService(ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public RoadMapService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { } diff --git a/LearningHub.Nhs.WebUI/Services/RoleService.cs b/LearningHub.Nhs.WebUI/Services/RoleService.cs index cfc3c8ff8..c4f37af65 100644 --- a/LearningHub.Nhs.WebUI/Services/RoleService.cs +++ b/LearningHub.Nhs.WebUI/Services/RoleService.cs @@ -21,9 +21,10 @@ public class RoleService : BaseService, IRoleService /// /// The cache service. /// Learning hub http client. + /// The Open Api Http Client. /// Logger. - public RoleService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + public RoleService(ICacheService cacheService, ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.cacheService = cacheService; } diff --git a/LearningHub.Nhs.WebUI/Services/SearchService.cs b/LearningHub.Nhs.WebUI/Services/SearchService.cs index 41ff87edb..578a5861f 100644 --- a/LearningHub.Nhs.WebUI/Services/SearchService.cs +++ b/LearningHub.Nhs.WebUI/Services/SearchService.cs @@ -34,11 +34,12 @@ public class SearchService : BaseService, ISearchService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// Provider service. /// Logger. /// Settings. - public SearchService(ILearningHubHttpClient learningHubHttpClient, IProviderService providerService, ILogger logger, IOptions settings) - : base(learningHubHttpClient, logger) + public SearchService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, IProviderService providerService, ILogger logger, IOptions settings) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.settings = settings.Value; this.providerService = providerService; @@ -163,10 +164,10 @@ public async Task PerformSearch(IPrincipal user, SearchRe { var filter = filters.Where(x => x.DisplayName == filteritem).FirstOrDefault(); - if (filter != null && UtilityHelper.FindwiseResourceTypeDict.ContainsKey(filter.DisplayName)) + if (filter != null && UtilityHelper.FindwiseResourceMoodleTypeDict.ContainsKey(filter.DisplayName)) { - var resourceTypeEnum = UtilityHelper.FindwiseResourceTypeDict[filter.DisplayName]; - var searchfilter = new SearchFilterModel() { DisplayName = UtilityHelper.GetPrettifiedResourceTypeName(resourceTypeEnum), Count = filter.Count, Value = filteritem, Selected = searchRequest.Filters?.Contains(filter.DisplayName) ?? false }; + 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 }; searchfilters.Add(searchfilter); } } @@ -345,7 +346,7 @@ public async Task CreateResourceSearchActionAsync(SearchActionResourceModel try { int createId = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(searchActionResourceModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -388,7 +389,7 @@ public async Task CreateCatalogueSearchActionAsync(SearchActionCatalogueMod try { int createId = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(searchActionCatalogueModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -427,7 +428,7 @@ public async Task CreateSearchTermEventAsync(SearchRequestModel searchReque try { int createId = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(searchRequestModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -467,7 +468,7 @@ public async Task GetSearchResultAsync(SearchRequestModel searc try { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); searchRequestModel.SearchText = this.DecodeProblemCharacters(searchRequestModel.SearchText); @@ -510,8 +511,8 @@ public async Task SubmitFeedbackAsync(SearchFeedBackModel model) { int createId = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); - var request = this.settings.LearningHubApiUrl + "Search/SubmitFeedback"; + var client = await this.OpenApiHttpClient.GetClientAsync(); + var request = $"Search/SubmitFeedback"; var content = new StringContent(JsonConvert.SerializeObject(model), Encoding.UTF8, "application/json"); var response = await client.PostAsync(request, content).ConfigureAwait(false); @@ -547,7 +548,7 @@ public async Task GetCatalogueSearchResultAsync(Catalo try { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); catalogueSearchRequestModel.SearchText = this.DecodeProblemCharacters(catalogueSearchRequestModel.SearchText); @@ -593,7 +594,7 @@ public async Task CreateCatalogueSearchTermEventAsync(CatalogueSearchReques try { int createId = 0; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(catalogueSearchRequestModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); @@ -637,7 +638,7 @@ public async Task GetAllCatalogueSearchResultAsync( try { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); catalogueSearchRequestModel.SearchText = this.DecodeProblemCharacters(catalogueSearchRequestModel.SearchText); @@ -680,7 +681,7 @@ public async Task GetAllCatalogueSearchResultAsync( /// The auto suggestion list. public async Task GetAutoSuggestionList(string term) { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Search/GetAutoSuggestionResult/{term}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -707,7 +708,7 @@ public async Task SendAutoSuggestionClickActionAsync(AutoSuggestionClickPayloadM { try { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var json = JsonConvert.SerializeObject(clickPayloadModel); var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); diff --git a/LearningHub.Nhs.WebUI/Services/SpecialtyService.cs b/LearningHub.Nhs.WebUI/Services/SpecialtyService.cs index adc3f41bb..4df5f36e7 100644 --- a/LearningHub.Nhs.WebUI/Services/SpecialtyService.cs +++ b/LearningHub.Nhs.WebUI/Services/SpecialtyService.cs @@ -19,13 +19,15 @@ public class SpecialtyService : BaseService, ISpecialtyService /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// . public SpecialtyService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/TermsAndConditionsService.cs b/LearningHub.Nhs.WebUI/Services/TermsAndConditionsService.cs index db00925e6..6c7220499 100644 --- a/LearningHub.Nhs.WebUI/Services/TermsAndConditionsService.cs +++ b/LearningHub.Nhs.WebUI/Services/TermsAndConditionsService.cs @@ -22,13 +22,15 @@ public class TermsAndConditionsService : BaseService, /// Initializes a new instance of the class. /// /// Learning hub http client. + /// The Open Api Http Client. /// User api http client. /// Logger. public TermsAndConditionsService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; } diff --git a/LearningHub.Nhs.WebUI/Services/UserGroupService.cs b/LearningHub.Nhs.WebUI/Services/UserGroupService.cs index 6790a3143..22729e5df 100644 --- a/LearningHub.Nhs.WebUI/Services/UserGroupService.cs +++ b/LearningHub.Nhs.WebUI/Services/UserGroupService.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using LearningHub.Nhs.Caching; + using LearningHub.Nhs.Models.Enums; using LearningHub.Nhs.Models.Extensions; using LearningHub.Nhs.Models.User; using LearningHub.Nhs.WebUI.Interfaces; @@ -25,17 +26,19 @@ public class UserGroupService : BaseService, IUserGroupService /// Initializes a new instance of the class. /// /// The learning hub http client. + /// The Open Api Http Client. /// The logger. /// The http context accessor. /// The cacheService. /// roleService. public UserGroupService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, ILogger logger, IHttpContextAccessor contextAccessor, ICacheService cacheService, IRoleService roleService) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.contextAccessor = contextAccessor; this.cacheService = cacheService; @@ -56,6 +59,18 @@ public async Task> GetRoleUserGroupDetailForUserAsy return await this.cacheService.GetOrFetchAsync(cacheKey, () => this.FetchRoleUserGroupDetailForUserAsync(userId)); } + /// + public async Task UserHasCatalogueContributionPermission() + { + var userRoleGroups = await this.GetRoleUserGroupDetailAsync(); + if (userRoleGroups != null && userRoleGroups.Any(r => r.RoleEnum == RoleEnum.Editor)) + { + return true; + } + + return false; + } + /// public async Task UserHasPermissionAsync(string permissionCode) { @@ -76,7 +91,7 @@ private async Task> FetchRoleUserGroupDetailAsync() { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserGroupRoleDetail"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -100,7 +115,7 @@ private async Task> FetchRoleUserGroupDetailForUser { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"UserGroup/GetUserGroupRoleDetailByUserId/{userId}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Services/UserService.cs b/LearningHub.Nhs.WebUI/Services/UserService.cs index a0ba11d9a..04a2bf68f 100644 --- a/LearningHub.Nhs.WebUI/Services/UserService.cs +++ b/LearningHub.Nhs.WebUI/Services/UserService.cs @@ -54,6 +54,7 @@ public class UserService : BaseService, IUserService /// Initializes a new instance of the class. /// /// The learningHubHttpClient. + /// The Open Api Http Client. /// The userApiHttpClient. /// The logger. /// The settings. @@ -66,6 +67,7 @@ public class UserService : BaseService, IUserService /// The login wizard service service. public UserService( ILearningHubHttpClient learningHubHttpClient, + IOpenApiHttpClient openApiHttpClient, IUserApiHttpClient userApiHttpClient, ILogger logger, IOptions settings, @@ -76,7 +78,7 @@ public UserService( ILocationService locationService, IGradeService gradeService, ILoginWizardService loginWizardService) - : base(learningHubHttpClient, logger) + : base(learningHubHttpClient, openApiHttpClient, logger) { this.userApiHttpClient = userApiHttpClient; this.settings = settings.Value; @@ -94,7 +96,7 @@ public async Task> GetActiveContentAsync() { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "User/GetActiveContent"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -334,7 +336,7 @@ public async Task GetCurrentUserProfileAsync() { UserProfile viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "User/GetCurrentUserProfile"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -359,7 +361,7 @@ public async Task GetUserProfileAsync(int userId) { UserProfile viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/GetUserProfile/{userId}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -387,7 +389,7 @@ public async Task CreateUserProfileAsync(UserProfil var json = JsonConvert.SerializeObject(userProfile); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/CreateUserProfile"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -422,7 +424,7 @@ public async Task UpdateUserProfileAsync(UserProfil var json = JsonConvert.SerializeObject(userProfile); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/UpdateUserProfile"; var response = await client.PutAsync(request, stringContent).ConfigureAwait(false); @@ -623,7 +625,7 @@ public async Task GetLHUserByUserIdAsync(int id) { UserLHBasicViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/GetByUserId/{id}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1094,7 +1096,7 @@ public async Task UpdateUserAsync(UserUpdateViewMod var json = JsonConvert.SerializeObject(userUpdateViewModel); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/UpdateUser"; @@ -1130,7 +1132,7 @@ public async Task CreateUserAsync(UserCreateViewMod var json = JsonConvert.SerializeObject(newLhUser); var stringContent = new StringContent(json, Encoding.UTF8, "application/json"); - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/CreateUser"; var response = await client.PostAsync(request, stringContent).ConfigureAwait(false); @@ -1566,7 +1568,7 @@ public async Task ValidateEmailChangeTokenAsyn { EmailChangeValidationTokenResult tokenResult = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/ValidateEmailChangeToken/{Uri.EscapeUriString(token.EncodeParameter())}/{Uri.EscapeUriString(loctoken.EncodeParameter())}/{isUserRoleUpgrade}"; @@ -1595,7 +1597,7 @@ public async Task GetLastIssuedEmailChangeV { EmailChangeValidationTokenViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = "User/GetLastIssuedEmailChangeValidationToken"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1620,7 +1622,7 @@ public async Task RegenerateEmailChangeVali { EmailChangeValidationTokenViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/ReGenerateEmailChangeValidationToken/{newPrimaryEmail}/{isUserRoleUpgrade}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1645,7 +1647,7 @@ public async Task CanRequestPasswordResetAsync(string emailAddress, int pa { bool status = false; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/CanRequestPasswordReset/{emailAddress}/{passwordRequestLimitingPeriod}/{passwordRequestLimit}"; var response = await client.GetAsync(request).ConfigureAwait(false); @@ -1670,7 +1672,7 @@ public async Task GenerateEmailChangeValida { EmailChangeValidationTokenViewModel viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/GenerateEmailChangeValidationTokenAndSendEmail/{emailAddress}/{isUserRoleUpgrade}"; @@ -1694,7 +1696,7 @@ public async Task GenerateEmailChangeValida /// public async Task CancelEmailChangeValidationTokenAsync() { - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"User/CancelEmailChangeValidationToken"; @@ -1844,7 +1846,7 @@ public async Task> GetProvidersByUserIdAsync(int userId) { List viewmodel = null; - var client = await this.LearningHubHttpClient.GetClientAsync(); + var client = await this.OpenApiHttpClient.GetClientAsync(); var request = $"Provider/GetProvidersByUserId/{userId}"; var response = await client.GetAsync(request).ConfigureAwait(false); diff --git a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs index fdab0fc8a..0a0c04c49 100644 --- a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs +++ b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs @@ -39,6 +39,14 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }); + services.AddHttpClient() + .ConfigurePrimaryHttpMessageHandler( + () => new HttpClientHandler + { + ServerCertificateCustomValidationCallback = + HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, + }); + services.AddHttpClient() .ConfigurePrimaryHttpMessageHandler( () => new HttpClientHandler @@ -65,6 +73,7 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon else { services.AddHttpClient(); + services.AddHttpClient(); services.AddHttpClient(); services.AddHttpClient(); services.AddHttpClient(); @@ -103,6 +112,7 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss index 1c18cc3cc..e7e49e651 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/common.scss @@ -1,80 +1,6 @@ @use "../abstracts/all" as *; @use "nhsuk" as *; -.nhsuk-u-font-style-italic { - font-style: italic; -} - -.nhsuk-button--red { - background-color: $nhsuk-red !important; - - &:hover { - background-color: $nhsuk-red-hover !important; - border-color: $nhsuk-red-hover !important; - } -} - -.nhsuk-button--beta-login { - background-color: $nhsuk-blue; - box-shadow: 0 4px 0 #002f5c; -} - -.nhsuk-button--beta-login:hover { - background-color: $nhsuk-btn-blue-hover; -} - -// By default, the text on reverse (white) buttons turns white once clicked, rendering them invisible. -.nhsuk-button--reverse:visited { - color: $nhsuk-black -} - -.nhsuk-back-link { - padding: px2rem(20) 0; - margin-bottom: 0; -} - -.nhsuk-radios__divider { - text-align: left; - width: unset; -} - -.nhsuk-radios__item label { - font-family: $font-stack; -} - -/* Conditional radio buttons - Note: The nhsuk-radios__conditional element needs to be a SIBLING of the radio button input element - otherwise the CSS selector won't work. See Views/Bookmark/Move.cshtml for a usage example. - The NHSUK component (nhsuk-radios__conditional) requires JavaScript to work. These tweaks allow it to work without. -*/ -.nhsuk-radios__conditional { - display: none; - margin-left: -22px; - margin-top: 8px; -} - -.nhsuk-radios__input:checked ~ .nhsuk-radios__conditional { - display: block !important; -} - -/* jquery unbobtrusive validation style over */ -.nhsuk-error-summary__list li { - color: $nhsuk-red; -} - -.nhsuk-form-group.input-validation-error { - @extend .nhsuk-form-group--error; -} - -.nhsuk-input.input-validation-error { - @extend .nhsuk-input--error -} - -.nhsuk-input:focus { - border: 2px solid #212b32; - box-shadow: inset 0 0 0 2px; - outline: 4px solid #ffeb3b; /* 1 */ - outline-offset: 0; -} .display--hide { display: none !important; @@ -120,92 +46,6 @@ } -.nhsuk-bg-light-blue { - background-color: $nhsuk-light-blue-color; -} - -.nhsuk-bg-pale-blue { - background-color: $nhsuk-pale-blue-color; -} - -.nhsuk-bg-white { - background-color: $color_nhsuk-white; -} - -.nhsuk-width-container.search-width-container { - max-width: px2rem(752); - margin: 0 auto; - padding-left: px2rem(68); - padding-right: px2rem(68); -} - -#maincontent { - - button[class^='nhsuk-search__submit'] span.nhsuk-u-visually-hidden { - color: $color_nhsuk-grey-1; - background-color: $color_nhsuk-white; - } -} - -form label.nhsuk-u-visually-hidden { - color: $color_nhsuk-grey-1; - background-color: $color_nhsuk-white; -} - -/* One third column layout that switches to full width at the small desktop breakpoint (990px) instead of mobile. */ -.nhsuk-grid-column-one-third-small-desktop { - @extend .nhsuk-grid-column-one-third; - width: 33.3333333333% !important; - - @media (max-width: px2rem(990)) { - width: 100% !important; - } -} - - -/* Tweaks to styling for single card view. */ -@media(min-width: 768px) and (max-width: 990px) { - .nhsuk-card-group .nhsuk-grid-column-one-third-small-desktop { - max-width: 600px !important; - } - - .nhsuk-card-group--centred { - justify-content: center !important; - } -} - -.nhsuk-card-banner-container { - padding-bottom: 42.86%; - position: relative; -} - -.nhsuk-card-banner { - height: 100%; - object-fit: cover; - object-position: left; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; -} - -.nhsuk-card-banner-empty { - background-color: $nhsuk-pale-blue-color; - border-bottom: 1px solid #d8dde0; -} - -.nhsuk-error-message.error-message--margin-bottom-1 { - margin-bottom: nhsuk-spacing(1); -} - -.nhsuk-u-margin-bottom-2point5 { - margin-bottom: 12px; - - @media(max-width: 641px) { - margin-bottom: 10px; - } -} .word-break__break-word { word-break: break-word; @@ -216,9 +56,7 @@ form label.nhsuk-u-visually-hidden { justify-content: space-between; } -.nhsuk-button--no-shrink { - white-space: nowrap; -} + .modal-footer--buttons { justify-content: space-between !important; @@ -233,14 +71,6 @@ form label.nhsuk-u-visually-hidden { box-shadow: 0 0 0 0.2rem $nhsuk-yellow !important; background-color: $govuk-focus-highlight-yellow; } -/*Add a background color to the radio button when focused */ -.nhsuk-radios__input:focus + .radioButton { - box-shadow: 0 0 0 3px $nhsuk-yellow; -} -/*Add a background color to the radio button when focused */ -.nhsuk-checkboxes__input:focus + .checkmark { - box-shadow: 0 0 0 4px $nhsuk-yellow; -} .accessible-link:focus { outline: none; diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss index 4cb2822fe..25b84b7d4 100644 --- a/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/layout.scss @@ -5,126 +5,11 @@ body { overflow-wrap: break-word; } -.nhsuk-header { - padding: 0 px2rem(32); -} - -.nhsuk-width-container.app-width-container { - max-width: px2rem(1208); - margin: 0 auto; - padding-left: px2rem(32); - padding-right: px2rem(32); -} - -.nhsuk-header .nhsuk-width-container.app-width-container { - max-width: px2rem(1144); - margin: 0 auto; -} - -.nhsuk-width-container.app-width-container.beta-banner { - padding: px2rem(8) px2rem(32); - max-width: px2rem(1208); - margin: 0 auto; -} - -.nhsuk-header .nhsuk-header__container::after { - content: none; -} - -.nhsuk-header__navigation.app-width-container { - max-width: px2rem(1144); -} - -.app-width-container--full { - margin: 0; - max-width: none -} .app-main-wrapper--no-padding { padding: 0 } -.nhsuk-header__container.app-width-container { - display: flex; - justify-content: space-between; - gap: 0 px2rem(24); - padding: px2rem(16) 0; -} - -.nhsuk-header__content { - display: flex; - align-items: center; - min-height: px2rem(40); - margin-left: auto; -} - -.nhsuk-header__logo { - flex: 1 0 0; -} - -.nhsuk-header__logo .nhsuk-header__link--service { - display: inline-flex; -} - -.nhsuk-header__service-name { - font-size: px2rem(19); -} - -.nhsuk-account__login { - font-size: px2rem(14); - float: right; - position: relative; - z-index: 2; - display: flex; - justify-content: space-between; - align-items: center; - gap: px2rem(24); -} - -.nhsuk-header__notification-dot { - position: absolute; - top: px2rem(8); - right: px2rem(-10); - font-size: px2rem(11); - line-height: px2rem(18); - font-weight: 900; - background: $nhsuk-error-color; - color: white; - min-width: px2rem(18); - height: px2rem(18); - text-align: center; - border-radius: px2rem(9); - padding: px2rem(1) px2rem(3) 0; -} - -.nhsuk-header__menu { - display: none; -} - -.nhsuk-header__search .nhsuk-search__input { - width: px2rem(260); -} - -.nhsuk-header__search { - .nhsuk-search__input { - width: px2rem(260); - - &::-moz-placeholder { - opacity: 1; - } - } - - #search > label.nhsuk-u-visually-hidden { - background-color: $nhsuk-white; - } -} - -.nhsuk-account__login--link, -.nhsuk-account__login--link:visited, -.nhsuk-account__login--link:hover { - color: #fff; -} - .beta-banner { background-color: $color_nhsuk-grey-5; color: $nhsuk-text-color; @@ -155,42 +40,6 @@ body { font-size: px2rem(16); } -.nhsuk-footer { - padding: px2rem(48) 0; -} - - -#header-dropdown-menu-control { - opacity: 0; - position: absolute; -} - -#header-dropdown-menu-control:checked ~ .nhsuk-header__navigation:not(.js-show) { - display: block -} - -#header-mobile-search-control { - display: none; -} - -.nhsuk-header__break { - display: none; -} - -.nhsuk-header__mobile-only-nav { - display: none; -} - -.nhsuk-header__mobile-break { - display: none; -} - -.nhsuk-header__navigation-item--current { - a { - font-weight: bold; - } -} - button[data-toggle="modal"] { color: #005eb8; padding: 0; @@ -254,347 +103,23 @@ button[data-toggle="modal"] { li.autosuggestion-option:last-of-type { border-bottom: none !important; } -/* large desktop */ -@media (min-width: px2rem(990)) { - - .nhsuk-header__navigation-item--current a { - border-bottom: 4px solid $nhsuk-grey-lighter; - font-weight: normal; - } - - .nhsuk-header__navigation-link { - position: relative; - } - - .nhsuk-header__navigation-item:last-child { - margin-right: 16px; - } -} /* small desktop */ @media (max-width: px2rem(989)) { - - .nhsuk-header__container { - flex-wrap: wrap; - } - - .nhsuk-header { - padding: 0; - } - - .nhsuk-header__container.app-width-container { - flex-wrap: wrap; - gap: 0 0; - padding: px2rem(16) px2rem(32); - } - - .nhsuk-header__link--service { - align-items: center; - -ms-flex-align: center; - margin-bottom: 0; - width: auto; - } - - .nhsuk-header__service-name { - padding-left: px2rem(16); - } - - .nhsuk-header__logo { - order: 0; - } - - .nhsuk-account__login { - order: 1; - margin-left: auto; - margin-right: 0px; - } - - .nhsuk-header__break { - display: block; - width: 100%; - height: px2rem(24); - order: 2 - } - - .nhsuk-header__search { - order: 3; - flex-grow: 1; - margin-left: 0; - margin-right: px2rem(24); - } - - .nhsuk-header__menu { - display: block; - position: relative; - order: 4; - flex: 0 0 px2rem(74); - } - - .nhsuk-header__navigation-list .nhsuk-header__navigation-item, - .nhsuk-header__navigation .nhsuk-header__navigation-title { - border-top: 1px solid $color_nhsuk-grey-4; - } - - .nhsuk-header__menu-toggle { - text-align: center; - margin: 0; - right: 0; - font-weight: 600; - } - - .nhsuk-header__search-form { - display: flex; - } - - .nhsuk-header__search .nhsuk-search__input { - flex: 1 0 0; - } - - #header-dropdown-menu-control:checked ~ .nhsuk-header__navigation:not(.js-show) { - display: block; - } - - .nhsuk-header__notification-dot { - position: absolute; - top: px2rem(15); - left: px2rem(115); - font-size: px2rem(11); - line-height: px2rem(18); - font-weight: 900; - background: $nhsuk-error-color; - color: $nhsuk-white; - min-width: px2rem(18); - width: fit-content; - height: px2rem(18); - text-align: center; - border-radius: px2rem(9); - } - - .nhsuk-header__navigation-item--current .nhsuk-header__notification-dot { - left: px2rem(125); - } - - .nhsuk-header__menu-notification-dot { - position: absolute; - top: px2rem(-5); - right: px2rem(-6); - background: $nhsuk-error-color; - width: px2rem(12); - height: px2rem(12); - border-radius: px2rem(6); - box-shadow: 0 0 0 2px white; - z-index: 10; - } - .autosuggestion-menu { top: 100%; } } - /* tablet */ @media (max-width: px2rem(768)) { - - .nhsuk-width-container.app-width-container, - .nhsuk-width-container.app-width-container.beta-banner { - padding-left: px2rem(16); - padding-right: px2rem(16); - } - - .nhsuk-back-link { - padding: 0.5rem 0; - } - - .nhsuk-header__menu .nhsuk-header__not-mobile { - display: none; - } - .autosuggestion-menu { top: 100%; } - - .nhsuk-header__not-mobile { - display: none; - } - - .nhsuk-header__mobile-only-nav { - display: flex; - order: 1; - justify-content: space-around; - gap: 0 px2rem(16); - align-items: flex-start; - flex-wrap: wrap; - width: px2rem(166); - } - - .nhsuk-header__mobile-only-nav .nhsuk-header__menu { - margin-right: px2rem(12); - } - - .nhsuk-header__mobile-only-nav .nhsuk-header__search-toggle { - margin-left: px2rem(12); - } - - .nhsuk-header__break { - display: none; - } - - .nhsuk-header__mobile-break { - display: block; - width: 100%; - height: 0; - } - - .nhsuk-header__link--service { - flex-direction: column; - align-items: flex-start; - } - - .nhsuk-header__notification-dot { - top: px2rem(13); - left: px2rem(100); - } - - .nhsuk-header__service-name { - padding: px2rem(12) 0 0; - } - - .nhsuk-header__search-toggle { - position: relative; - height: px2rem(40); - order: 2; - padding: px2rem(7) px2rem(10) 0; - margin: 0 - } - - .nhsuk-header__search .nhsuk-search__submit { - padding-top: nhsuk-spacing(1); - } - - .nhsuk-header__menu { - order: 3; - } - - .nhsuk-header__search { - order: 4; - width: 100%; - flex-grow: 1; - margin: px2rem(16) px2rem(-16) 0; - border-bottom: 1px solid $color_nhsuk-grey-4; - } - - #header-mobile-search-control { - display: block; - opacity: 0; - position: absolute; - } - - #header-mobile-search-control:checked ~ .nhsuk-header__search .nhsuk-header__search-wrap { - display: block; - } - - .nhsuk-width-container.nhsuk-header__container.app-width-container { - padding-bottom: 0; - } } /* mobile */ @media (max-width: px2rem(640)) { - - .nhsuk-header__not-mobile { - display: none; - } - - .nhsuk-header__logo { - max-width: none; - } - - .nhsuk-header__mobile-only-nav { - display: flex; - order: 1; - justify-content: space-around; - gap: 0 px2rem(16); - align-items: flex-start; - flex-wrap: wrap; - width: px2rem(166); - } - - .nhsuk-header__pre-login .nhsuk-header__mobile-only-nav { - align-items: center; - justify-content: flex-end; - padding-bottom: px2rem(16); - } - - .nhsuk-header__mobile-only-nav .nhsuk-header__menu { - margin-right: px2rem(12); - } - - .nhsuk-header__mobile-only-nav .nhsuk-header__search-toggle { - margin-left: px2rem(12); - } - - .nhsuk-header__break { - display: none; - } - - .nhsuk-header__mobile-break { - display: block; - width: 100%; - height: 0; - } - - .nhsuk-header__link--service { - flex-direction: column; - align-items: flex-start; - } - - .nhsuk-header__notification-dot { - top: px2rem(13); - left: px2rem(100); - } - - .nhsuk-header__service-name { - padding: px2rem(12) 0 0; - } - - .nhsuk-header__search-toggle { - position: relative; - height: px2rem(40); - order: 2; - padding: px2rem(7) px2rem(10) 0; - margin: 0 - } - - .nhsuk-header__search .nhsuk-search__submit { - padding-top: nhsuk-spacing(1); - } - - .nhsuk-header__menu { - order: 3; - } - - .nhsuk-header__search { - order: 4; - width: 100%; - flex-grow: 1; - margin: px2rem(16) px2rem(-16) 0; - border-bottom: 1px solid $color_nhsuk-grey-4; - } - - #header-mobile-search-control { - display: block; - opacity: 0; - position: absolute; - } - - #header-mobile-search-control:checked ~ .nhsuk-header__search .nhsuk-header__search-wrap { - display: block; - } - - .nhsuk-width-container.nhsuk-header__container.app-width-container { - padding-bottom: 0; - } - .autosuggestion-menu { top: 100%; } -} \ No newline at end of file +} diff --git a/LearningHub.Nhs.WebUI/Styles/nhsuk/nhsuk-overrides.scss b/LearningHub.Nhs.WebUI/Styles/nhsuk/nhsuk-overrides.scss new file mode 100644 index 000000000..22c319751 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Styles/nhsuk/nhsuk-overrides.scss @@ -0,0 +1,672 @@ +@use "../abstracts/all" as *; +@use "nhsuk" as *; + +.nhsuk-u-font-style-italic { + font-style: italic; +} + +.nhsuk-button--red { + background-color: $nhsuk-red !important; + + &:hover { + background-color: $nhsuk-red-hover !important; + border-color: $nhsuk-red-hover !important; + } +} + +.nhsuk-button--beta-login { + background-color: $nhsuk-blue; + box-shadow: 0 4px 0 #002f5c; +} + +.nhsuk-button--beta-login:hover { + background-color: $nhsuk-btn-blue-hover; +} + +// By default, the text on reverse (white) buttons turns white once clicked, rendering them invisible. +.nhsuk-button--reverse:visited { + color: $nhsuk-black +} + +.nhsuk-back-link { + padding: px2rem(20) 0; + margin-bottom: 0; +} + +.nhsuk-radios__divider { + text-align: left; + width: unset; +} + +.nhsuk-radios__item label { + font-family: $font-stack; +} + +/* Conditional radio buttons - Note: The nhsuk-radios__conditional element needs to be a SIBLING of the radio button input element + otherwise the CSS selector won't work. See Views/Bookmark/Move.cshtml for a usage example. + The NHSUK component (nhsuk-radios__conditional) requires JavaScript to work. These tweaks allow it to work without. +*/ +.nhsuk-radios__conditional { + display: none; + margin-left: -22px; + margin-top: 8px; +} + +.nhsuk-radios__input:checked ~ .nhsuk-radios__conditional { + display: block !important; +} + +/* jquery unbobtrusive validation style over */ +.nhsuk-error-summary__list li { + color: $nhsuk-red; +} + +.nhsuk-form-group.input-validation-error { + @extend .nhsuk-form-group--error; +} + +.nhsuk-input.input-validation-error { + @extend .nhsuk-input--error +} + +.nhsuk-input:focus { + border: 2px solid #212b32; + box-shadow: inset 0 0 0 2px; + outline: 4px solid #ffeb3b; /* 1 */ + outline-offset: 0; +} + +.nhsuk-bg-light-blue { + background-color: $nhsuk-light-blue-color; +} + +.nhsuk-bg-pale-blue { + background-color: $nhsuk-pale-blue-color; +} + +.nhsuk-bg-white { + background-color: $color_nhsuk-white; +} + +.nhsuk-width-container.search-width-container { + max-width: px2rem(752); + margin: 0 auto; + padding-left: px2rem(68); + padding-right: px2rem(68); +} + +#maincontent { + button[class^='nhsuk-search__submit'] span.nhsuk-u-visually-hidden { + color: $color_nhsuk-grey-1; + background-color: $color_nhsuk-white; + } +} + +form label.nhsuk-u-visually-hidden { + color: $color_nhsuk-grey-1; + background-color: $color_nhsuk-white; +} + +/* One third column layout that switches to full width at the small desktop breakpoint (990px) instead of mobile. */ +.nhsuk-grid-column-one-third-small-desktop { + @extend .nhsuk-grid-column-one-third; + width: 33.3333333333% !important; + + @media (max-width: px2rem(990)) { + width: 100% !important; + } +} + + +/* Tweaks to styling for single card view. */ +@media(min-width: 768px) and (max-width: 990px) { + .nhsuk-card-group .nhsuk-grid-column-one-third-small-desktop { + max-width: 600px !important; + } + + .nhsuk-card-group--centred { + justify-content: center !important; + } +} + +.nhsuk-card-banner-container { + padding-bottom: 42.86%; + position: relative; +} + +.nhsuk-card-banner { + height: 100%; + object-fit: cover; + object-position: left; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.nhsuk-card-banner-empty { + background-color: $nhsuk-pale-blue-color; + border-bottom: 1px solid #d8dde0; +} + +.nhsuk-error-message.error-message--margin-bottom-1 { + margin-bottom: nhsuk-spacing(1); +} + +.nhsuk-u-margin-bottom-2point5 { + margin-bottom: 12px; + + @media(max-width: 641px) { + margin-bottom: 10px; + } +} + +.nhsuk-button--no-shrink { + white-space: nowrap; +} + +/*Add a background color to the radio button when focused */ +.nhsuk-radios__input:focus + .radioButton { + box-shadow: 0 0 0 3px $nhsuk-yellow; +} +/*Add a background color to the radio button when focused */ +.nhsuk-checkboxes__input:focus + .checkmark { + box-shadow: 0 0 0 4px $nhsuk-yellow; +} + + + +// Below taken from layout.scss +// Overrides largely due to +// - Highly customised header +// - Use of full browser width hero images and full width colour bands +// - Beta banner +// +// Header customisation not needed with current frontend package +// - FGC 19/06/25 + + +.nhsuk-width-container.app-width-container { + max-width: px2rem(1208); + margin: 0 auto; + padding-left: px2rem(32); + padding-right: px2rem(32); +} + +// Header items +.nhsuk-header { + padding: 0 px2rem(32); +} + +.nhsuk-header .nhsuk-width-container.app-width-container { + max-width: px2rem(1144); + margin: 0 auto; +} + +.nhsuk-width-container.app-width-container.beta-banner { + padding: px2rem(8) px2rem(32); + max-width: px2rem(1208); + margin: 0 auto; +} + +.nhsuk-header .nhsuk-header__container::after { + content: none; +} + +.nhsuk-header__navigation.app-width-container { + max-width: px2rem(1144); +} + +.nhsuk-header__container.app-width-container { + display: flex; + justify-content: space-between; + gap: 0 px2rem(24); + padding: px2rem(16) 0; +} + +.nhsuk-header__logo { + flex: 1 0 0; +} + +.nhsuk-header__logo .nhsuk-header__link--service { + display: inline-flex; +} + +.nhsuk-header__service-name { + font-size: px2rem(19); +} + +.nhsuk-header__notification-dot { + position: absolute; + top: px2rem(8); + right: px2rem(-10); + font-size: px2rem(11); + line-height: px2rem(18); + font-weight: 900; + background: $nhsuk-error-color; + color: white; + min-width: px2rem(18); + height: px2rem(18); + text-align: center; + border-radius: px2rem(9); + padding: px2rem(1) px2rem(3) 0; +} + +.nhsuk-header__menu { + display: none; +} + +.nhsuk-header__search .nhsuk-search__input { + width: px2rem(260); +} + +.nhsuk-header__search { + .nhsuk-search__input { + width: px2rem(260); + + &::-moz-placeholder { + opacity: 1; + } + } + + #search > label.nhsuk-u-visually-hidden { + background-color: $nhsuk-white; + } +} + +#header-dropdown-menu-control { + opacity: 0; + position: absolute; +} + + +#header-dropdown-menu-control:checked ~ .nhsuk-header__navigation:not(.js-show) { + display: block +} + +#header-mobile-search-control { + display: none; +} + +.nhsuk-header__break { + display: none; +} + +.nhsuk-header__mobile-only-nav { + display: none; +} + +.nhsuk-header__mobile-break { + display: none; +} + +.nhsuk-header__navigation-item--current { + a { + font-weight: bold; + } +} + +.nhsuk-account__login { + // also a header item + font-size: px2rem(14); + float: right; + position: relative; + z-index: 2; + display: flex; + justify-content: space-between; + align-items: center; + gap: px2rem(24); +} + +.nhsuk-account__login--link, +.nhsuk-account__login--link:visited, +.nhsuk-account__login--link:hover { + // all header items + color: #fff; +} + + +// End of header items + + +.nhsuk-width-container.app-width-container--full { + // used to allow placement of hero (full width) images + margin: 0; + max-width: none +} + +.app-main-wrapper--no-padding { + // allowing hero image to touch headers + padding: 0 +} + +.nhsuk-footer { + padding: px2rem(48) 0; +} + + + +/* large desktop */ +@media (min-width: px2rem(990)) { + // entirely headers + + .nhsuk-header__navigation-item--current a { + border-bottom: 4px solid $nhsuk-grey-lighter; + font-weight: normal; + } + + .nhsuk-header__navigation-link { + position: relative; + } + + .nhsuk-header__navigation-item:last-child { + margin-right: 16px; + } +} + +/* small desktop */ +@media (max-width: px2rem(989)) { + + //entirely headers + + .nhsuk-header__container { + flex-wrap: wrap; + } + + .nhsuk-header { + padding: 0; + } + + .nhsuk-header__container.app-width-container { + flex-wrap: wrap; + gap: 0 0; + padding: px2rem(16) px2rem(32); + } + + .nhsuk-header__link--service { + align-items: center; + -ms-flex-align: center; + margin-bottom: 0; + width: auto; + } + + .nhsuk-header__service-name { + padding-left: px2rem(16); + } + + .nhsuk-header__logo { + order: 0; + } + + .nhsuk-account__login { + // also part of the header + order: 1; + margin-left: auto; + margin-right: 0px; + } + + .nhsuk-header__break { + display: block; + width: 100%; + height: px2rem(24); + order: 2 + } + + .nhsuk-header__search { + order: 3; + flex-grow: 1; + margin-left: 0; + margin-right: px2rem(24); + } + + .nhsuk-header__menu { + display: block; + position: relative; + order: 4; + flex: 0 0 px2rem(74); + } + + .nhsuk-header__navigation-list .nhsuk-header__navigation-item, + .nhsuk-header__navigation .nhsuk-header__navigation-title { + border-top: 1px solid $color_nhsuk-grey-4; + } + + .nhsuk-header__menu-toggle { + text-align: center; + margin: 0; + right: 0; + font-weight: 600; + } + + .nhsuk-header__search-form { + display: flex; + } + + .nhsuk-header__search .nhsuk-search__input { + flex: 1 0 0; + } + + #header-dropdown-menu-control:checked ~ .nhsuk-header__navigation:not(.js-show) { + display: block; + } + + .nhsuk-header__notification-dot { + position: absolute; + top: px2rem(15); + left: px2rem(115); + font-size: px2rem(11); + line-height: px2rem(18); + font-weight: 900; + background: $nhsuk-error-color; + color: $nhsuk-white; + min-width: px2rem(18); + width: fit-content; + height: px2rem(18); + text-align: center; + border-radius: px2rem(9); + } + + .nhsuk-header__navigation-item--current .nhsuk-header__notification-dot { + left: px2rem(125); + } + + .nhsuk-header__menu-notification-dot { + position: absolute; + top: px2rem(-5); + right: px2rem(-6); + background: $nhsuk-error-color; + width: px2rem(12); + height: px2rem(12); + border-radius: px2rem(6); + box-shadow: 0 0 0 2px white; + z-index: 10; + } +} + +@media (max-width: px2rem(768)) { + .nhsuk-width-container.app-width-container, + .nhsuk-width-container.app-width-container.beta-banner { + padding-left: px2rem(16); + padding-right: px2rem(16); + } + + // entirely headers from this point + + .nhsuk-back-link { + padding: 0.5rem 0; + } + + .nhsuk-header__menu .nhsuk-header__not-mobile { + display: none; + } + + .nhsuk-header__not-mobile { + display: none; + } + + .nhsuk-header__mobile-only-nav { + display: flex; + order: 1; + justify-content: space-around; + gap: 0 px2rem(16); + align-items: flex-start; + flex-wrap: wrap; + width: px2rem(166); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__menu { + margin-right: px2rem(12); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__search-toggle { + margin-left: px2rem(12); + } + + .nhsuk-header__break { + display: none; + } + + .nhsuk-header__mobile-break { + display: block; + width: 100%; + height: 0; + } + + .nhsuk-header__link--service { + flex-direction: column; + align-items: flex-start; + } + + .nhsuk-header__notification-dot { + top: px2rem(13); + left: px2rem(100); + } + + .nhsuk-header__service-name { + padding: px2rem(12) 0 0; + } + + .nhsuk-header__search-toggle { + position: relative; + height: px2rem(40); + order: 2; + padding: px2rem(7) px2rem(10) 0; + margin: 0 + } + + .nhsuk-header__search .nhsuk-search__submit { + padding-top: nhsuk-spacing(1); + } + + .nhsuk-header__menu { + order: 3; + } + + .nhsuk-header__search { + order: 4; + width: 100%; + flex-grow: 1; + margin: px2rem(16) px2rem(-16) 0; + border-bottom: 1px solid $color_nhsuk-grey-4; + } +} + +@media (max-width: px2rem(640)) { + + //entirely headers + + .nhsuk-header__not-mobile { + display: none; + } + + .nhsuk-header__logo { + max-width: none; + } + + .nhsuk-header__mobile-only-nav { + display: flex; + order: 1; + justify-content: space-around; + gap: 0 px2rem(16); + align-items: flex-start; + flex-wrap: wrap; + width: px2rem(166); + } + + .nhsuk-header__pre-login .nhsuk-header__mobile-only-nav { + align-items: center; + justify-content: flex-end; + padding-bottom: px2rem(16); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__menu { + margin-right: px2rem(12); + } + + .nhsuk-header__mobile-only-nav .nhsuk-header__search-toggle { + margin-left: px2rem(12); + } + + .nhsuk-header__break { + display: none; + } + + .nhsuk-header__mobile-break { + display: block; + width: 100%; + height: 0; + } + + .nhsuk-header__link--service { + flex-direction: column; + align-items: flex-start; + } + + .nhsuk-header__notification-dot { + top: px2rem(13); + left: px2rem(100); + } + + .nhsuk-header__service-name { + padding: px2rem(12) 0 0; + } + + .nhsuk-header__search-toggle { + position: relative; + height: px2rem(40); + order: 2; + padding: px2rem(7) px2rem(10) 0; + margin: 0 + } + + .nhsuk-header__search .nhsuk-search__submit { + padding-top: nhsuk-spacing(1); + } + + .nhsuk-header__menu { + order: 3; + } + + .nhsuk-header__search { + order: 4; + width: 100%; + flex-grow: 1; + margin: px2rem(16) px2rem(-16) 0; + border-bottom: 1px solid $color_nhsuk-grey-4; + } + + #header-mobile-search-control { + display: block; + opacity: 0; + position: absolute; + } + + #header-mobile-search-control:checked ~ .nhsuk-header__search .nhsuk-header__search-wrap { + display: block; + } + + .nhsuk-width-container.nhsuk-header__container.app-width-container { + padding-bottom: 0; + } +} diff --git a/LearningHub.Nhs.WebUI/Styles/sections/_all.scss b/LearningHub.Nhs.WebUI/Styles/sections/_all.scss index 22c55622d..a127ade9d 100644 --- a/LearningHub.Nhs.WebUI/Styles/sections/_all.scss +++ b/LearningHub.Nhs.WebUI/Styles/sections/_all.scss @@ -140,268 +140,272 @@ div.contribute { } div.contribute { - h2 { - .warningTriangle { - padding-left: 10px; - vertical-align: middle; - } - } - - h3 { - .warningTriangle { - padding-left: 10px; - vertical-align: middle; - } - } - - div.common-content { - div.form-group { - margin-bottom: 0; + h2 { + .warningTriangle { + padding-left: 10px; + vertical-align: middle; + } } - .bg-grey-white { - padding: 17px 25px 30px 25px; - color: $nhsuk-black; + h3 { + .warningTriangle { + padding-left: 10px; + vertical-align: middle; + } } - } - div.white-background { - background-color: $nhsuk-white; - min-height: 420px; - } - - .limit-width { - width: 100%; - max-width: 850px; - margin-left: 40px; - padding-right: 50px; - } + div.common-content { + div.form-group { + margin-bottom: 0; + } - div.contribute-header { - .draftText { - color: $nhsuk-green; - margin-top: 0; + .bg-grey-white { + padding: 17px 25px 30px 25px; + color: $nhsuk-black; + } } - .error-message { - color: $nhsuk-red; - font-weight: bold; + div.white-background { + background-color: $nhsuk-white; + min-height: 420px; } - .warning-banner { - display: flex; - flex-flow: row; - justify-content: space-between; - padding: 1.5rem 1.5rem 0.8rem 1.5rem; - border-bottom: 1px solid $nhsuk-grey-light; - border-top: 1px solid $nhsuk-grey-light; - - div.warningTriangle { - font-size: 40px; - } - - div.info { - padding-left: 12px; - } - - div.dismiss { - text-align: end; - padding-top: .5rem; - padding-right: 2rem; - - button { - font-size: 2.5rem; - color: $nhsuk-grey; - } - } - - .warning-banner-left { - display: flex; - justify-content: space-between; + .limit-width { width: 100%; - max-width: 800px; + max-width: 850px; margin-left: 40px; - } + padding-right: 50px; } - } - .warningTriangle { - color: #ffb81c; - font-size: 2rem; + div.contribute-header { + .draftText { + color: $nhsuk-green; + margin-top: 0; + } - &.large { - font-size: 4rem !important; - } - } + .error-message { + color: $nhsuk-red; + font-weight: bold; + } - button.delete-button { - text-decoration: none; - color: $nhsuk-grey-placeholder; - font-size: 1.6rem; + .warning-banner { + display: flex; + flex-flow: row; + justify-content: space-between; + padding: 1.5rem 1.5rem 0.8rem 1.5rem; + border-bottom: 1px solid $nhsuk-grey-light; + border-top: 1px solid $nhsuk-grey-light; + + div.warningTriangle { + font-size: 40px; + } - i { - margin-right: 4px; - font-size: 1.8rem; - } - } + div.info { + padding-left: 12px; + } - button.publish-button { - color: $nhsuk-white; - background-color: $nhsuk-green; - font-size: 19px; - text-align: center !important; - border: 1px solid $nhsuk-green !important; - min-height: 50px; - min-width: 115px; - padding: 0px 25px 0px 25px; - border-radius: 5px; - } + div.dismiss { + text-align: end; + padding-top: .5rem; + padding-right: 2rem; - button.publish-button:disabled { - background-color: $nhsuk-grey; - border-color: $nhsuk-grey !important; - } + button { + font-size: 2.5rem; + color: $nhsuk-grey; + } + } - button.btn-outline-custom:disabled { - color: $nhsuk-grey !important; - border-color: $nhsuk-grey !important; - } + .warning-banner-left { + display: flex; + justify-content: space-between; + width: 100%; + max-width: 800px; + margin-left: 40px; + } + } + } - button.btn-outline-custom:disabled:hover { - background-color: $nhsuk-white !important; - } + .warningTriangle { + color: #ffb81c; + font-size: 2rem; - div.resource-area-container, div.common-content { - div.resource-area-header { - background-color: $nhsuk-grey; - color: $nhsuk-grey-white; - border-top-left-radius: .5rem; - border-top-right-radius: .5rem; - font-family: $font-stack-bold; - padding: 1.4rem 2rem 1.0rem 2rem; - display: flex; - justify-content: space-between; + &.large { + font-size: 4rem !important; + } + } - a, - button { + button.delete-button { text-decoration: none; - font-size: 19px; - font-family: $font-stack; - color: $nhsuk-grey-white !important; - padding-top: 0; + color: $nhsuk-grey-placeholder; + font-size: 1.6rem; i { - margin-left: 4px; + margin-right: 4px; + font-size: 1.8rem; } - } } - div.resource-area-body { - background-color: $nhsuk-grey-white; - border-bottom-left-radius: .5rem; - border-bottom-right-radius: .5rem; - min-height: 300px; - padding: 20px 10px 20px 10px; + button.publish-button { + color: $nhsuk-white; + background-color: $nhsuk-green; + font-size: 19px; + text-align: center !important; + border: 1px solid $nhsuk-green !important; + min-height: 50px; + min-width: 115px; + padding: 0px 25px 0px 25px; + border-radius: 5px; } - .radio-options { - height: 12px !important; - width: 12px !important; - border: 1px solid $nhsuk-black; - color: $nhsuk-black; + button.publish-button:disabled { + background-color: $nhsuk-grey; + border-color: $nhsuk-grey !important; } - .radio-options-text { - margin-right: 20px; + button.btn-outline-custom:disabled { + color: $nhsuk-grey !important; + border-color: $nhsuk-grey !important; } - .author-details, .file-details, .licence-details { - display: flex; - justify-content: space-between; - background-color: $nhsuk-white; - border-radius: 5px; - padding: 25px; + button.btn-outline-custom:disabled:hover { + background-color: $nhsuk-white !important; + } - button, - a { - font-size: 16px; - color: $nhsuk-red; - text-decoration: none; - display: flex; - justify-content: space-between; + div.resource-area-container, div.common-content { + div.resource-area-header { + background-color: $nhsuk-grey; + color: $nhsuk-grey-white; + border-top-left-radius: .5rem; + border-top-right-radius: .5rem; + font-family: $font-stack-bold; + padding: 1.4rem 2rem 1.0rem 2rem; + display: flex; + justify-content: space-between; - i { - padding-left: 10px; - padding-top: 3px; + a, + button { + text-decoration: none; + font-size: 19px; + font-family: $font-stack; + color: $nhsuk-grey-white !important; + padding-top: 0; + + i { + margin-left: 4px; + } + } } - } - .divider { - color: $nhsuk-grey-light; - } - } + div.resource-area-body { + background-color: $nhsuk-grey-white; + border-bottom-left-radius: .5rem; + border-bottom-right-radius: .5rem; + min-height: 300px; + padding: 20px 10px 20px 10px; + } - .author-details { - border: solid 1px $nhsuk-grey-light; - padding: 22px 15px 10px 15px; + .radio-options { + height: 12px !important; + width: 12px !important; + border: 1px solid $nhsuk-black; + color: $nhsuk-black; + } - i { - color: $nhsuk-grey; - margin-right: 1rem; - } - } + .radio-options-text { + margin-right: 20px; + } - .keyword-container { - display: flex; - flex-wrap: wrap; + .author-details, .file-details, .licence-details { + display: flex; + justify-content: space-between; + background-color: $nhsuk-white; + border-radius: 5px; + padding: 25px; + + button, + a { + font-size: 16px; + color: $nhsuk-red; + text-decoration: none; + display: flex; + justify-content: space-between; + + i { + padding-left: 10px; + padding-top: 3px; + } + } - .keyword-tag { - background-color: $nhsuk-grey-white; - border-radius: 20px; - margin-bottom: 10px; - padding: 8px 10px 3px 15px; + .divider { + color: $nhsuk-grey-light; + } + } - button { - color: $nhsuk-red; - font-size: 2rem; + .author-details { + border: solid 1px $nhsuk-grey-light; + padding: 22px 15px 10px 15px; + + i { + color: $nhsuk-grey; + margin-right: 1rem; + } } - } - } - span.optional { - font-family: $font-stack; - } + .keyword-label { + font-weight: normal; + } + + .keyword-container { + display: flex; + flex-wrap: wrap; + + .keyword-tag { + background-color: $nhsuk-grey-white; + border-radius: 20px; + margin-bottom: 10px; + padding: 8px 10px 3px 15px; + + button { + color: $nhsuk-red; + font-size: 2rem; + } + } + } + + span.optional { + font-family: $font-stack; + } - textarea { - width: 100%; + textarea { + width: 100%; + } } - } - .authored-date label { - font-size: 1.6rem; - } + .authored-date label { + font-size: 1.6rem; + } - div.publish-warning { - display: flex; - flex-direction: row; + div.publish-warning { + display: flex; + flex-direction: row; - .triangle { - margin-right: 10px; - display: flex; - align-items: center; + .triangle { + margin-right: 10px; + display: flex; + align-items: center; - i { - padding-top: 5px; - } + i { + padding-top: 5px; + } + } } - } - div.highlighted-info { - background-color: rgba(255, 184, 28, 0.05); - border: 1px solid #FFB81C; - padding: 15px 24px; - margin: 15px 15px 0 15px; - } + div.highlighted-info { + background-color: rgba(255, 184, 28, 0.05); + border: 1px solid #FFB81C; + padding: 15px 24px; + margin: 15px 15px 0 15px; + } } @media (max-width: 768px) { diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/AccessRequested.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/AccessRequested.cshtml index 3fa90a2ae..10f2af3dd 100644 --- a/LearningHub.Nhs.WebUI/Views/Catalogue/AccessRequested.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Catalogue/AccessRequested.cshtml @@ -13,7 +13,7 @@

Access requested

-

Your request to access this cataloque has seen sent to the cataloque administrator.

+

Your request to access this catalogue has seen sent to the catalogue administrator.

What happens next?

The catalogue administrator will review your request and you will be notified of their decision by email.

diff --git a/LearningHub.Nhs.WebUI/Views/Home/Dashboard.cshtml b/LearningHub.Nhs.WebUI/Views/Home/Dashboard.cshtml index 4a7b55c08..e8481a4c7 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/Dashboard.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/Dashboard.cshtml @@ -5,7 +5,15 @@ @{ ViewData["Title"] = "Learning Hub - Home"; - var isReadOnly = User.IsInRole("ReadOnly") || User.IsInRole("BasicUser"); + var isReadOnly = false; + if (User.IsInRole("ReadOnly") || User.IsInRole("BasicUser")) + { + isReadOnly = true; + } + else if (User.IsInRole("BlueUser") && !this.ViewBag.userHasContributePermission) + { + isReadOnly = true; + } } @section styles { diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml index 058c39165..68ad72564 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml @@ -12,7 +12,7 @@ { var apiBaseUrl = Configuration["MoodleAPIConfig:BaseUrl"]; string path = $"course/view.php"; - string returnUrl = $@"{apiBaseUrl}/{path}?id={courseId}"; + string returnUrl = $@"{apiBaseUrl}{path}?id={courseId}"; return returnUrl; } @@ -21,11 +21,9 @@
@if (!string.IsNullOrWhiteSpace(Model.CourseImage)) { - if (Model.CourseImage.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) + @if (Model.CourseImage.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) { - - Fallback image - + Course image } else { @@ -60,7 +58,7 @@
@if (@Model?.Progress != null) { -
Progress: @Model.Progress%
+
Progress: @Model.ProgressPercentage
}
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml index ea636286c..647583787 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml @@ -1,4 +1,5 @@ @model LearningHub.Nhs.WebUI.Models.Search.SearchResultViewModel +@inject Microsoft.Extensions.Configuration.IConfiguration Configuration; @using System.Linq; @using System.Web; @@ -10,99 +11,124 @@ @using LearningHub.Nhs.Models.Search.SearchClick; @{ - var resourceResult = Model.ResourceSearchResult; - var pagingModel = Model.ResourceResultPaging; - var index = pagingModel.CurrentPage * pagingModel.PageSize; - var searchString = HttpUtility.UrlEncode(Model.SearchString); - - string GetUrl(int resourceReferenceId, int itemIndex, int nodePathId, SearchClickPayloadModel payload) - { - var searchSignal = payload?.SearchSignal; - string groupId = HttpUtility.UrlEncode(Model.GroupId.ToString()); - string searchSignalQueryEncoded = HttpUtility.UrlEncode(HttpUtility.UrlDecode(searchSignal?.Query)); - - return $@"/search/record-resource-click?url=/Resource/{resourceReferenceId}&nodePathId={nodePathId}&itemIndex={payload?.HitNumber} + var resourceResult = Model.ResourceSearchResult; + var pagingModel = Model.ResourceResultPaging; + var index = pagingModel.CurrentPage * pagingModel.PageSize; + var searchString = HttpUtility.UrlEncode(Model.SearchString); + + string GetUrl(int resourceReferenceId, int itemIndex, int nodePathId, SearchClickPayloadModel payload) + { + var searchSignal = payload?.SearchSignal; + string groupId = HttpUtility.UrlEncode(Model.GroupId.ToString()); + string searchSignalQueryEncoded = HttpUtility.UrlEncode(HttpUtility.UrlDecode(searchSignal?.Query)); + + return $@"/search/record-resource-click?url=/Resource/{resourceReferenceId}&nodePathId={nodePathId}&itemIndex={payload?.HitNumber} &pageIndex={pagingModel.CurrentPage}&totalNumberOfHits={payload?.SearchSignal?.Stats?.TotalHits}&searchText={searchString}&resourceReferenceId={resourceReferenceId} &groupId={groupId}&searchId={searchSignal?.SearchId}&timeOfSearch={searchSignal?.TimeOfSearch}&userQuery={HttpUtility.UrlEncode(searchSignal.UserQuery)} &query={searchSignalQueryEncoded}&title={payload?.DocumentFields?.Title}"; - } + } + + string GetMoodleCourseUrl(string courseId) + { + var prefix = "M"; + if (courseId.StartsWith(prefix)) + { + courseId = courseId.Replace(prefix, ""); ; + } + + var apiBaseUrl = Configuration["MoodleAPIConfig:BaseUrl"]; + string path = $"course/view.php"; + string returnUrl = $@"{apiBaseUrl}{path}?id={courseId}"; - bool showCatalogueFieldsInResources = ViewBag.ShowCatalogueFieldsInResources == null || ViewBag.ShowCatalogueFieldsInResources == true; - bool resourceAccessLevelFilterSelected = resourceResult.SearchResourceAccessLevelFilters.Any(f => f.Selected); + return returnUrl; + } + + bool showCatalogueFieldsInResources = ViewBag.ShowCatalogueFieldsInResources == null || ViewBag.ShowCatalogueFieldsInResources == true; + bool resourceAccessLevelFilterSelected = resourceResult.SearchResourceAccessLevelFilters.Any(f => f.Selected); } @foreach (var item in resourceResult.DocumentModel) { - var provider = item.Providers?.FirstOrDefault(); - -
-

- @item.Title -

- - @if (provider != null) - { -
-
- - @ProviderHelper.GetProviderString(provider.Name) -
-
- } - @if (item.CatalogueRestrictedAccess && !Model.HideRestrictedBadge && showCatalogueFieldsInResources) - { -

- @((item.CatalogueHasAccess || this.User.IsInRole("Administrator")) ? "Access Granted" : "Access restricted") -

- } - - @if (!resourceAccessLevelFilterSelected) - { -
-
- Audience access level: - @ResourceAccessLevelHelper.GetResourceAccessLevelText((ResourceAccessibilityEnum)item.ResourceAccessLevel) -
-
- } - - -
-
- Type: - @UtilityHelper.GetPrettifiedResourceTypeName(UtilityHelper.ToEnum(item.ResourceType), 0) -
-
- @await Html.PartialAsync("../Shared/_StarRating.cshtml", item.Rating) -
-
- -

- @item.Description -

- -
- @if (!string.IsNullOrWhiteSpace(item.CatalogueBadgeUrl) && showCatalogueFieldsInResources) - { - Provider's catalogue badge - } - - @if (!string.IsNullOrEmpty(item.CatalogueName) && !this.Model.CatalogueId.HasValue && showCatalogueFieldsInResources) - { - - } - -
- @UtilityHelper.GetAttribution(item.Authors) - @if (!string.IsNullOrEmpty(item.AuthoredDate)) - { - @UtilityHelper.GetInOn(item.AuthoredDate) - @: @item.AuthoredDate - } -
-
-
- index++; + var provider = item.Providers?.FirstOrDefault(); + +
+

+ @if (item.ResourceType == "moodle") + { + @item.Title + } + else + { + @item.Title + } +

+ + @if (provider != null) + { +
+
+ + @ProviderHelper.GetProviderString(provider.Name) +
+
+ } + @if (item.CatalogueRestrictedAccess && !Model.HideRestrictedBadge && showCatalogueFieldsInResources) + { +

+ @((item.CatalogueHasAccess || this.User.IsInRole("Administrator")) ? "Access Granted" : "Access restricted") +

+ } + + @if (!resourceAccessLevelFilterSelected) + { +
+
+ Audience access level: + @ResourceAccessLevelHelper.GetResourceAccessLevelText((ResourceAccessibilityEnum)item.ResourceAccessLevel) +
+
+ } + + +
+
+ Type: + @UtilityHelper.GetPrettifiedResourceTypeNameMoodle(UtilityHelper.ToEnum(item.ResourceType), 0) +
+
+ @if (item.ResourceType != "moodle") + { + @await Html.PartialAsync("../Shared/_StarRating.cshtml", item.Rating) + } +
+
+ +

+ @item.Description +

+ +
+ @if (!string.IsNullOrWhiteSpace(item.CatalogueBadgeUrl) && showCatalogueFieldsInResources) + { + Provider's catalogue badge + } + + @if (!string.IsNullOrEmpty(item.CatalogueName) && !this.Model.CatalogueId.HasValue && showCatalogueFieldsInResources) + { + + } + +
+ @UtilityHelper.GetAttribution(item.Authors) + @if (!string.IsNullOrEmpty(item.AuthoredDate)) + { + @UtilityHelper.GetInOn(item.AuthoredDate) + @: @item.AuthoredDate + } +
+
+
+ index++; } \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml index a0139e3eb..da4a475e9 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_SearchBar.cshtml @@ -48,8 +48,8 @@ function autocomplete(input, minLength) { if (input != null) { input.addEventListener("input", function () { - var val = this.value; - if (val.length < minLength) { + var val = this.value.trimStart(); + if (val.length < minLength || val.trim() === "") { closeAllLists(); return false; } diff --git a/LearningHub.Nhs.WebUI/Views/Shared/Components/NavigationItems/Searchbar.cshtml b/LearningHub.Nhs.WebUI/Views/Shared/Components/NavigationItems/Searchbar.cshtml index 8f7f8a738..f3a69f8e6 100644 --- a/LearningHub.Nhs.WebUI/Views/Shared/Components/NavigationItems/Searchbar.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Shared/Components/NavigationItems/Searchbar.cshtml @@ -72,8 +72,8 @@ function autocomplete(input, minLength) { if (input != null) { input.addEventListener("input", function () { - var val = this.value; - if (val.length < minLength) { + var val = this.value.trimStart(); + if (val.length < minLength || val.trim() === "") { closeAllLists(); return false; } diff --git a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml index b999a6fb2..6b679b67e 100644 --- a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml @@ -21,6 +21,7 @@ +