Courses
- @foreach (MoodleSubCategoryResponseModel item in Model.SubCategories)
+ @foreach (MoodleCategory item in Model.SubCategories)
{
diff --git a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
index 1384acfb9..d08f7769d 100644
--- a/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
+++ b/LearningHub.Nhs.WebUI/Views/Catalogue/Index.cshtml
@@ -57,8 +57,8 @@
if (ViewBag.ActiveTab == "courses")
{
- if (Model.Catalogue.SelectedCategoryId == 0 ||
- (Model.Catalogue.SelectedCategoryId > 0 &&
+ if (Model.Catalogue.SelectedCategoryId == null ||
+ (Model.Catalogue.SelectedCategoryId != null &&
(Model.Courses == null || !Model.Courses.Any()) &&
(Model.SubCategories == null || !Model.SubCategories.Any())))
{
@@ -71,7 +71,7 @@
{
breadcrumbs = UtilityHelper.GetBreadcrumbsForFolderNodes(Model.NodePathNodes.SkipLast(1).ToList(), Model.Catalogue.Url);
}
- else if (ViewBag.ActiveTab == "courses" && Model.Catalogue.SelectedCategoryId > 0)
+ else if (ViewBag.ActiveTab == "courses" && Model.Catalogue.SelectedCategoryId !=null)
{
breadcrumbs = UtilityHelper.GetBreadcrumbsForCourses(Model.MoodleCategories, Model.Catalogue.Url);
}
@@ -205,7 +205,7 @@
Resources
}
- @if (Model.Catalogue.SelectedCategoryId > 0 &&
+ @if (Model.Catalogue.SelectedCategoryId != null &&
(
(Model.Courses != null && Model.Courses.Any()) ||
(Model.SubCategories != null && Model.SubCategories.Any())
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleBridgeConfig.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleBridgeConfig.cs
new file mode 100644
index 000000000..4798fabe8
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleBridgeConfig.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LearningHub.Nhs.OpenApi.Models.Configuration
+{
+ ///
+ /// The Moodle Bridge Settings.
+ ///
+ public class MoodleBridgeAPIConfig
+ {
+ ///
+ /// Gets or sets the base url for the Moodle service.
+ ///
+ public string BaseUrl { get; set; } = null!;
+
+ ///
+ /// Gets or sets the token.
+ ///
+ public string Token { get; set; } = null!;
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
index 829bba059..a7ecc8897 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Models/LearningHub.Nhs.OpenApi.Models.csproj
@@ -17,8 +17,12 @@
-
+
+
+
+
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories.Interface/LearningHub.Nhs.OpenApi.Repositories.Interface.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories.Interface/LearningHub.Nhs.OpenApi.Repositories.Interface.csproj
index cbac27a64..acfceeb83 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories.Interface/LearningHub.Nhs.OpenApi.Repositories.Interface.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories.Interface/LearningHub.Nhs.OpenApi.Repositories.Interface.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/LearningHub.Nhs.OpenApi.Repositories.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/LearningHub.Nhs.OpenApi.Repositories.csproj
index 6a727dc60..33302f623 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/LearningHub.Nhs.OpenApi.Repositories.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/LearningHub.Nhs.OpenApi.Repositories.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Hierarchy/CatalogueNodeVersionRepository.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Hierarchy/CatalogueNodeVersionRepository.cs
index 3367b371f..32932e648 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Hierarchy/CatalogueNodeVersionRepository.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Repositories/Repositories/Hierarchy/CatalogueNodeVersionRepository.cs
@@ -226,12 +226,14 @@ public async Task AddCategoryToCatalogueAsync(int userId, CatalogueViewModel vm)
{
try
{
+ var (instanceName, categoryId) = vm.SelectedCategoryId.Split(':') is var p && p.Length == 2 ? (p[0], p[1]) : (null, null);
var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = userId };
var param1 = new SqlParameter("@p1", SqlDbType.Int) { Value = vm.CatalogueNodeVersionId };
- var param2 = new SqlParameter("@p2", SqlDbType.Int) { Value = vm.SelectedCategoryId };
- var param3 = new SqlParameter("@p3", SqlDbType.Int) { Value = TimezoneOffsetManager.UserTimezoneOffset ?? (object)DBNull.Value };
+ var param2 = new SqlParameter("@p2", SqlDbType.Int) { Value = categoryId };
+ var param3 = new SqlParameter("@p3", SqlDbType.VarChar) { Value = instanceName };
+ var param4 = new SqlParameter("@p4", SqlDbType.Int) { Value = TimezoneOffsetManager.UserTimezoneOffset ?? (object)DBNull.Value };
- await DbContext.Database.ExecuteSqlRawAsync("hierarchy.CatalogueNodeVersionCategoryCreate @p0, @p1, @p2, @p3", param0, param1, param2, param3);
+ await DbContext.Database.ExecuteSqlRawAsync("hierarchy.CatalogueNodeVersionCategoryCreate @p0, @p1, @p2, @p3, @p4", param0, param1, param2, param3, param4);
}
catch (Exception ex)
{
@@ -249,9 +251,10 @@ public async Task RemoveCategoryFromCatalogueAsync(int userId, CatalogueViewMode
{
try
{
+ var (instanceName, categoryId) = vm.SelectedCategoryId.Split(':') is var p && p.Length == 2 ? (p[0], p[1]) : (null, null);
var param0 = new SqlParameter("@p0", SqlDbType.Int) { Value = userId };
var param1 = new SqlParameter("@p1", SqlDbType.Int) { Value = vm.CatalogueNodeVersionId };
- var param2 = new SqlParameter("@p2", SqlDbType.Int) { Value = vm.SelectedCategoryId };
+ var param2 = new SqlParameter("@p2", SqlDbType.Int) { Value = categoryId };
var param3 = new SqlParameter("@p3", SqlDbType.Int) { Value = TimezoneOffsetManager.UserTimezoneOffset ?? (object)DBNull.Value };
await DbContext.Database.ExecuteSqlRawAsync("hierarchy.RemoveCatalogueCategory @p0, @p1, @p2, @p3", param0, param1, param2, param3);
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/HttpClients/IMoodleBridgeHttpClient.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/HttpClients/IMoodleBridgeHttpClient.cs
new file mode 100644
index 000000000..129d3eec3
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/HttpClients/IMoodleBridgeHttpClient.cs
@@ -0,0 +1,25 @@
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace LearningHub.Nhs.OpenApi.Services.Interface.HttpClients
+{
+ ///
+ /// The Moodle Http Client interface.
+ ///
+ public interface IMoodleBridgeHttpClient
+ {
+ ///
+ /// The get cient async.
+ ///
+ ///
The .
+ Task
GetClient();
+
+ ///
+ /// GETs data from Databricks API.
+ ///
+ /// The URL to make a get call to.
+ /// Optional authorization header.
+ /// A representing the result of the asynchronous operation.
+ Task GetData(string requestUrl, string? authHeader);
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
index 175ac7fb3..802661079 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/LearningHub.Nhs.OpenApi.Services.Interface.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/ICategoryService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/ICategoryService.cs
index 5c4a994a4..2ac311640 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/ICategoryService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/ICategoryService.cs
@@ -14,6 +14,6 @@ public interface ICategoryService
///
/// node version id.
/// A representing the result of the asynchronous operation.
- Task GetByCatalogueVersionIdAsync(int nodeVersionId);
+ Task GetByCatalogueVersionIdAsync(int nodeVersionId);
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IDashboardService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IDashboardService.cs
index 7897acf90..ff04ae056 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IDashboardService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IDashboardService.cs
@@ -21,13 +21,11 @@ public interface IDashboardService
///
/// Get My in progress courses and Elearning.
///
- /// The dashboardTrayLearningResource type.
- /// The dashboard type.
- /// The page Number.
+ /// The requestModel.
/// The userId.
/// The resourceType.
/// A representing the result of the asynchronous operation.
- Task GetMyCoursesAndElearning(string dashboardTrayLearningResourceType, string dashboardType, int pageNumber, int userId, string resourceType);
+ Task GetMyCoursesAndElearning(GetMyCoursesAndElearningRequestModel requestModel, int userId, string resourceType);
///
/// Gets the user in progrss my leraning activities..
@@ -35,8 +33,9 @@ public interface IDashboardService
/// The dashboardTrayLearningResourceType.
/// The pageNumber.
/// The user id.
+ /// The email.
/// The .
- Task GetMyInprogressLearningAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId);
+ Task GetMyInprogressLearningAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId, string email);
///
/// Gets the resource certificate details.
@@ -45,7 +44,7 @@ public interface IDashboardService
/// The user id.
/// The resourceType.
/// The .
- Task GetUserCertificateDetailsAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId);
+ Task GetUserCertificateDetailsAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId, string email);
///
/// GetResources.
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleBridgeApiService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleBridgeApiService.cs
new file mode 100644
index 000000000..a3aa57b0d
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleBridgeApiService.cs
@@ -0,0 +1,82 @@
+
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using LearningHub.Nhs.Models.Moodle;
+using LearningHub.Nhs.Models.Moodle.API;
+using LearningHub.Nhs.Models.MyLearning;
+
+namespace LearningHub.Nhs.OpenApi.Services.Interface.Services
+{
+ ///
+ /// IMoodleBridgeApiService.
+ ///
+ public interface IMoodleBridgeApiService
+ {
+ ///
+ /// GetUserInstancesByEmailAsync.
+ ///
+ /// The current LH User email.
+ /// A representing the result of the asynchronous operation.
+ Task GetUserInstancesByEmail(string email);
+
+ ///
+ /// GetRecentEnrolledCoursesAsync.
+ ///
+ /// The moodleUserInstanceUserIds.
+ /// The requestModel.
+ /// The month.
+ ///
+ Task GetRecentEnrolledCoursesAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, MyLearningRequestModel requestModel, int? month = null);
+
+ ///
+ /// GetAllMoodleCategoriesAsync.
+ ///
+ /// A representing the result of the asynchronous operation.
+ Task> GetAllMoodleCategoriesAsync();
+
+ ///
+ /// GetEnrolledCoursesAsync.
+ ///
+ /// Moodle Instances user id.
+ /// MyLearningRequestModel requestModel.
+ /// A representing the result of the asynchronous operation.
+ Task GetEnrolledCoursesHistoryAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, MyLearningRequestModel requestModel);
+
+ ///
+ /// GetInProgressEnrolledCoursesAsync.
+ ///
+ /// The email.
+ /// A representing the result of the asynchronous operation.
+ Task GetInProgressEnrolledCoursesAsync(string email);
+
+ ///
+ /// GetUserLearningHistory.
+ ///
+ /// user email.
+ /// The filterText.
+ /// A representing the result of the asynchronous operation.
+ Task GetUserCertificateAsync(string email, string filterText = "");
+
+ ///
+ /// GetUserCertificateFromMoodleInstancesAsync.
+ ///
+ /// Moodle Instances user id.
+ /// filterText.
+ /// A representing the result of the asynchronous operation.
+ Task GetUserCertificateFromMoodleInstancesAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, string filterText = "");
+
+ ///
+ /// GetCoursesByCategoryIdAsync.
+ ///
+ /// The categoryId.
+ ///
+ Task GetCoursesByCategoryIdAsync(string categoryId);
+
+ ///
+ /// GetSubCategoryByCategoryIdAsync.
+ ///
+ /// The categoryId.
+ ///
+ Task> GetSubCategoryByCategoryIdAsync(string categoryId);
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMyLearningService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMyLearningService.cs
index 04a68d86f..aabdc0d99 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMyLearningService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMyLearningService.cs
@@ -26,7 +26,7 @@ public interface IMyLearningService
/// /// The user id.
/// The request model.
/// The .
- Task GetUserRecentMyLearningActivitiesAsync(int userId, MyLearningRequestModel requestModel);
+ Task GetUserRecentMyLearningActivitiesAsync(int userId, MyLearningApiRequestViewModel requestModel);
///
/// Gets history of users my leraning activities.
@@ -34,7 +34,7 @@ public interface IMyLearningService
/// /// The user id.
/// The request model.
/// The .
- Task GetUserLearningHistoryAsync(int userId, MyLearningRequestModel requestModel);
+ Task GetUserLearningHistoryAsync(int userId, MyLearningApiRequestViewModel requestModel);
///
/// Gets the played segment data for the progress modal in My Learning screen.
@@ -69,6 +69,6 @@ public interface IMyLearningService
/// The user id.
/// The request model
/// The .
- Task GetUserCertificateDetails(int userId, MyLearningRequestModel requestModel);
+ Task GetUserCertificateDetails(int userId, MyLearningApiRequestViewModel requestModel);
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Helpers/MoodleInstanceUsersHelper.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Helpers/MoodleInstanceUsersHelper.cs
new file mode 100644
index 000000000..de3272ec0
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Helpers/MoodleInstanceUsersHelper.cs
@@ -0,0 +1,47 @@
+namespace LearningHub.Nhs.OpenApi.Services.Helpers
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using LearningHub.Nhs.Models.Enums;
+ using LearningHub.Nhs.Models.Moodle;
+ using LearningHub.Nhs.Models.Resource;
+ using LearningHub.Nhs.Models.Resource.Blocks;
+
+ ///
+ /// A class containing helper functions for building moodle user instances.
+ ///
+ public class MoodleInstanceUsersHelper
+ {
+ ///
+ /// BuildMoodleUserInstances.
+ ///
+ ///
+ ///
+ public static MoodleInstanceUserIdsViewModel BuildUserIdsByInstance(
+ IEnumerable mappings)
+ {
+ var dict = new Dictionary(StringComparer.OrdinalIgnoreCase);
+
+ foreach (var m in mappings)
+ {
+ if (m?.User is null) continue;
+ if (m.User.Id <= 0) continue;
+
+ var key = string.IsNullOrWhiteSpace(m.Instance)
+ ? $"instance_{m.User.Id}"
+ : m.Instance!;
+
+ if (!dict.ContainsKey(key))
+ {
+ dict[key] = m.User.Id;
+ }
+ }
+
+ return new MoodleInstanceUserIdsViewModel
+ {
+ MoodleInstanceUserIds = dict
+ };
+ }
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleBridgeHttpClient.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleBridgeHttpClient.cs
new file mode 100644
index 000000000..e7812294d
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleBridgeHttpClient.cs
@@ -0,0 +1,97 @@
+using IdentityModel.Client;
+using LearningHub.Nhs.Models.Entities.Reporting;
+using LearningHub.Nhs.OpenApi.Models.Configuration;
+using LearningHub.Nhs.OpenApi.Services.Interface.HttpClients;
+using Microsoft.Extensions.Options;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Net.Http.Headers;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LearningHub.Nhs.OpenApi.Services.HttpClients
+{
+ ///
+ /// The Moodle Http Client.
+ ///
+ public class MoodleBridgeHttpClient : IMoodleBridgeHttpClient, IDisposable
+ {
+ private readonly MoodleBridgeAPIConfig moodleBridgeApiConfig;
+ private readonly HttpClient httpClient = new();
+
+ private bool initialised = false;
+ private string moodleBridgeApiUrl;
+ private string moodleBridgeApiToken;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// httpClient.
+ /// config.
+ public MoodleBridgeHttpClient(HttpClient httpClient, IOptions moodleBridgeApiConfig)
+ {
+ this.moodleBridgeApiConfig = moodleBridgeApiConfig.Value;
+ this.httpClient = httpClient;
+
+ this.moodleBridgeApiUrl = this.moodleBridgeApiConfig.BaseUrl;
+ this.moodleBridgeApiToken = this.moodleBridgeApiConfig.Token;
+ }
+
+ ///
+ /// The Get Client method.
+ ///
+ /// The .
+ public async Task GetClient()
+ {
+ this.Initialise(this.moodleBridgeApiUrl);
+ return this.httpClient;
+ }
+
+
+ ///
+ public void Dispose()
+ {
+ this.Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// The dispoase.
+ ///
+ /// disposing.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ this.httpClient.Dispose();
+ }
+ }
+
+ private void Initialise(string httpClientUrl)
+ {
+ if (this.initialised == false)
+ {
+ this.httpClient.BaseAddress = new Uri(httpClientUrl);
+ this.httpClient.DefaultRequestHeaders.Accept.Clear();
+ this.httpClient.DefaultRequestHeaders.Accept.Add(
+ new MediaTypeWithQualityHeaderValue("application/json"));
+ this.httpClient.DefaultRequestHeaders.Add("X-API-KEY", moodleBridgeApiToken);
+ this.initialised = true;
+ }
+ }
+
+ ///
+ public async Task GetData(string requestUrl, string? authHeader)
+ {
+ if (!string.IsNullOrEmpty(authHeader))
+ {
+ this.httpClient.SetBearerToken(authHeader);
+ }
+
+ var message = await this.httpClient.GetAsync(requestUrl).ConfigureAwait(false);
+ return message;
+ }
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
index 36c6d8f5f..793271d39 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj
@@ -31,7 +31,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
index 5edfe8cc4..0dfb757e7 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CatalogueService.cs
@@ -229,7 +229,11 @@ public async Task GetCatalogueAsync(int id)
// Used by the admin screen to inform the admin user if they need to add a user group.
vm.HasUserGroup = this.GetRoleUserGroupsForCatalogue(vm.NodeId).Any();
vm.Providers = await this.providerService.GetAllAsync();
- vm.SelectedCategoryId = await this.categoryService.GetByCatalogueVersionIdAsync(vm.CatalogueNodeVersionId);
+ var cataloguNodeeCategories = await this.categoryService.GetByCatalogueVersionIdAsync(vm.CatalogueNodeVersionId);
+ if (cataloguNodeeCategories != null)
+ {
+ vm.SelectedCategoryId = cataloguNodeeCategories.InstanceName + ":" + cataloguNodeeCategories.CategoryId;
+ }
return vm;
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CategoryService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CategoryService.cs
index e950a1d1f..32b5dfdda 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CategoryService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/CategoryService.cs
@@ -36,10 +36,10 @@ public CategoryService(ICategoryRepository categoryRepository, IMapper mapper)
}
///
- public async Task GetByCatalogueVersionIdAsync(int nodeVersionId)
+ public async Task GetByCatalogueVersionIdAsync(int nodeVersionId)
{
var category = await categoryRepository.GetCategoryByCatalogueIdAsync(nodeVersionId);
- return category != null ? category.CategoryId : 0;
+ return category;
}
}
}
\ No newline at end of file
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/DashboardService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/DashboardService.cs
index ad7868baf..5da2bc71b 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/DashboardService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/DashboardService.cs
@@ -35,6 +35,11 @@ public class DashboardService : IDashboardService
///
private readonly IMoodleApiService moodleApiService;
+ ///
+ /// The moodleBridgeApiService.
+ ///
+ private readonly IMoodleBridgeApiService moodleBridgeApiService;
+
///
/// The resourceActivityRepository.
///
@@ -54,9 +59,10 @@ public class DashboardService : IDashboardService
/// ratingService.
/// providerService.
/// moodleApiService.
+ /// moodleBridgeApiService.
/// resourceActivityRepository.
/// resourceRepository.
- public DashboardService(IMapper mapper, IResourceVersionRepository resourceVersionRepository, ICatalogueNodeVersionRepository catalogueNodeVersionRepository, IRatingService ratingService, IProviderService providerService, IMoodleApiService moodleApiService, IResourceActivityRepository resourceActivityRepository, IResourceRepository resourceRepository)
+ public DashboardService(IMapper mapper, IResourceVersionRepository resourceVersionRepository, ICatalogueNodeVersionRepository catalogueNodeVersionRepository, IRatingService ratingService, IProviderService providerService, IMoodleApiService moodleApiService, IMoodleBridgeApiService moodleBridgeApiService, IResourceActivityRepository resourceActivityRepository, IResourceRepository resourceRepository)
{
this.mapper = mapper;
this.resourceVersionRepository = resourceVersionRepository;
@@ -66,6 +72,7 @@ public DashboardService(IMapper mapper, IResourceVersionRepository resourceVersi
this.moodleApiService = moodleApiService;
this.resourceActivityRepository = resourceActivityRepository;
this.resourceRepository = resourceRepository;
+ this.moodleBridgeApiService = moodleBridgeApiService;
}
///
@@ -126,28 +133,28 @@ public async Task GetMyAccessLearnings(str
/// The userId.
/// The resourceType.
/// A representing the result of the asynchronous operation.
- public async Task GetMyCoursesAndElearning(string dashboardTrayLearningResourceType, string dashboardType, int pageNumber, int userId, string resourceType)
+ public async Task GetMyCoursesAndElearning(GetMyCoursesAndElearningRequestModel requestModel, int userId, string resourceType)
{
MyLearningActivitiesDetailedViewModel myInProgressActivities = new();
MyLearningCertificatesDetailedViewModel certificates = new();
List resources = new();
int resourceCount = 0;
- if (dashboardType == "my-in-progress")
+ if (requestModel.DashboardType == "my-in-progress")
{
- myInProgressActivities = await this.GetMyInprogressLearningAsync(dashboardTrayLearningResourceType, pageNumber, userId);
+ myInProgressActivities = await this.GetMyInprogressLearningAsync(requestModel.DashboardTrayLearningResourceType, requestModel.PageNumber, userId, requestModel.Email);
}
- else if (dashboardType == "my-certificates")
+ else if (requestModel.DashboardType == "my-certificates")
{
- certificates = await this.GetUserCertificateDetailsAsync(dashboardTrayLearningResourceType, pageNumber, userId);
+ certificates = await this.GetUserCertificateDetailsAsync(requestModel.DashboardTrayLearningResourceType, requestModel.PageNumber, userId, requestModel.Email);
}
else
{
- var result = resourceVersionRepository.GetResources(dashboardType, pageNumber, userId);
+ var result = resourceVersionRepository.GetResources(requestModel.DashboardType, requestModel.PageNumber, userId);
resourceCount = result.resourceCount;
resources = result.resources ?? new List();
}
- var cataloguesResponse = dashboardType.ToLower() == "my-catalogues" ? catalogueNodeVersionRepository.GetCatalogues(dashboardType, pageNumber, userId) : (TotalCount: 0, Catalogues: new List());
+ var cataloguesResponse = requestModel.DashboardType.ToLower() == "my-catalogues" ? catalogueNodeVersionRepository.GetCatalogues(requestModel.DashboardType, requestModel.PageNumber, userId) : (TotalCount: 0, Catalogues: new List());
var catalogueList = cataloguesResponse.Catalogues.Any() ? mapper.Map>(cataloguesResponse.Catalogues) : new List();
if (catalogueList.Any())
@@ -196,19 +203,19 @@ public async Task GetMyCoursesAndElearning
var response = new DashboardMyLearningResponseViewModel
{
- Type = dashboardType,
+ Type = requestModel.DashboardType,
Resources = resourceList,
Catalogues = catalogueList,
Activities = myInProgressActivities.Activities,
UserCertificates = certificates.Certificates,
- TotalCount = dashboardType?.ToLower() switch
+ TotalCount = requestModel.DashboardType?.ToLower() switch
{
"my-catalogues" => cataloguesResponse.TotalCount,
"my-in-progress" => myInProgressActivities?.TotalCount ?? 0,
"my-certificates" => certificates?.TotalCount ?? 0,
_ => resourceCount
},
- CurrentPage = pageNumber,
+ CurrentPage = requestModel.PageNumber,
};
return response;
@@ -220,11 +227,12 @@ public async Task GetMyCoursesAndElearning
/// The dashboardTrayLearningResourceType.
/// The pageNumber.
/// The user id.
+ /// The email.
/// The .
- public async Task GetMyInprogressLearningAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId)
+ public async Task GetMyInprogressLearningAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId, string email)
{
List result = new();
- List entrolledCourses = new();
+ MoodleCompletionsApiResponseModel entrolledCourses = new();
List mappedMyLearningActivities = new();
List mappedEnrolledCourses = new();
if (dashboardTrayLearningResourceType != "courses")
@@ -234,7 +242,7 @@ public async Task GetMyInprogressLearning
if (dashboardTrayLearningResourceType != "elearning")
{
- entrolledCourses = await this.moodleApiService.GetInProgressEnrolledCoursesAsync(userId);
+ entrolledCourses = await this.moodleBridgeApiService.GetInProgressEnrolledCoursesAsync(email);
}
if (result != null)
@@ -269,36 +277,39 @@ public async Task GetMyInprogressLearning
if (entrolledCourses != null)
{
- mappedEnrolledCourses = entrolledCourses.Select(course => new MyLearningCombinedActivitiesViewModel
- {
- UserId = userId,
- ResourceId = (int)course.Id,
- ResourceVersionId = (int)course.Id,
- IsCurrentResourceVersion = true,
- ResourceReferenceId = (int)course.Id,
- MajorVersion = 1,
- MinorVersion = 0,
- ResourceType = ResourceTypeEnum.Moodle,
- Title = course.DisplayName,
- CertificateEnabled = course.CertificateEnabled,
- ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
- ActivityDate = course.LastAccessDate.HasValue
+ mappedEnrolledCourses = entrolledCourses?.Results?
+ .Where(r => r.Data?.Courses != null)
+ .SelectMany(r => r.Data.Courses)
+ .Select(course => new MyLearningCombinedActivitiesViewModel
+ {
+ UserId = userId,
+ ResourceId = (int)course.Id,
+ ResourceVersionId = (int)course.Id,
+ IsCurrentResourceVersion = true,
+ ResourceReferenceId = (int)course.Id,
+ MajorVersion = 1,
+ MinorVersion = 0,
+ ResourceType = ResourceTypeEnum.Moodle,
+ Title = course.DisplayName,
+ CertificateEnabled = course.CertificateEnabled,
+ ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
+ ActivityDate = course.LastAccessDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(course.LastAccessDate.Value)
: DateTimeOffset.MinValue,
- ScorePercentage = Convert.ToInt32(course.ProgressPercentage.TrimEnd('%')),
- TotalActivities = course.TotalActivities,
- CompletedActivities = course.CompletedActivities,
- IsMostRecent = false,
- ResourceDurationMilliseconds = 0,
- CompletionPercentage = 0,
- ProvidersJson = null,
- AssesmentScore = 0,
- AssessmentPassMark = 0,
- AssessmentType = 0,
- CertificateAwardedDate = course.EndDate.HasValue
+ ScorePercentage = Convert.ToInt32(course.ProgressPercentage.TrimEnd('%')),
+ TotalActivities = course.TotalActivities,
+ CompletedActivities = course.CompletedActivities,
+ IsMostRecent = false,
+ ResourceDurationMilliseconds = 0,
+ CompletionPercentage = 0,
+ ProvidersJson = null,
+ AssesmentScore = 0,
+ AssessmentPassMark = 0,
+ AssessmentType = 0,
+ CertificateAwardedDate = course.EndDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(course.EndDate.Value)
: DateTimeOffset.MinValue,
- }).ToList();
+ }).ToList();
}
// Combine both result sets
@@ -327,16 +338,16 @@ public async Task GetMyInprogressLearning
/// The pageNumber.
/// The user id.
/// The .
- public async Task GetUserCertificateDetailsAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId)
+ public async Task GetUserCertificateDetailsAsync(string dashboardTrayLearningResourceType, int pageNumber, int userId, string email)
{
try
{
- Task>? courseCertificatesTask = null;
Task>? resourceCertificatesTask = null;
+ Task? courseCertificatesTask = null;
if (dashboardTrayLearningResourceType != "elearning")
{
- courseCertificatesTask = moodleApiService.GetUserCertificateAsync(userId);
+ courseCertificatesTask = moodleBridgeApiService.GetUserCertificateAsync(email);
}
if (dashboardTrayLearningResourceType != "courses")
@@ -361,23 +372,24 @@ public async Task GetUserCertificateDet
if (courseCertificatesTask != null)
{
- var courseCertificates = courseCertificatesTask.Result ?? Enumerable.Empty();
-
- mappedCourseCertificates = courseCertificates.Select(c => new UserCertificateViewModel
- {
- Title = string.IsNullOrWhiteSpace(c.ResourceTitle) ? c.ResourceName : c.ResourceTitle,
- ResourceTypeId = (int)ResourceTypeEnum.Moodle,
- ResourceReferenceId = 0,
- MajorVersion = 0,
- MinorVersion = 0,
- AwardedDate = c.AwardedDate.HasValue
+ mappedCourseCertificates = courseCertificatesTask.Result?.Results?
+ .Where(r => r.Data?.Certificates != null)
+ .SelectMany(r => r.Data.Certificates)
+ .Select(c => new UserCertificateViewModel
+ {
+ Title = string.IsNullOrWhiteSpace(c.ResourceTitle) ? c.ResourceName : c.ResourceTitle,
+ ResourceTypeId = (int)ResourceTypeEnum.Moodle,
+ ResourceReferenceId = 0,
+ MajorVersion = 0,
+ MinorVersion = 0,
+ AwardedDate = c.AwardedDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(c.AwardedDate.Value)
: DateTimeOffset.MinValue,
- CertificatePreviewUrl = c.PreviewLink,
- CertificateDownloadUrl = c.DownloadLink,
- ResourceVersionId = 0,
- ProvidersJson = null
- });
+ CertificatePreviewUrl = c.PreviewLink,
+ CertificateDownloadUrl = c.DownloadLink,
+ ResourceVersionId = 0,
+ ProvidersJson = null
+ });
}
var allCertificates = resourceCertificates.Concat(mappedCourseCertificates);
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs
index 9630ff24d..f868d946a 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs
@@ -43,7 +43,7 @@ public MoodleApiService(IMoodleHttpClient moodleHttpClient, ILoggerUserId from Moodle.
public async Task GetMoodleUserIdByUsernameAsync(int currentUserId)
{
- var parameters = new Dictionary
+ var parameters = new Dictionary
{
{ "criteria[0][key]", "username" },
{ "criteria[0][value]", currentUserId.ToString() }
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleBridgeApiService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleBridgeApiService.cs
new file mode 100644
index 000000000..57fab7f83
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleBridgeApiService.cs
@@ -0,0 +1,560 @@
+namespace LearningHub.Nhs.OpenApi.Services.Services
+{
+ using LearningHub.Nhs.Models.Moodle;
+ using LearningHub.Nhs.Models.Moodle.API;
+ using LearningHub.Nhs.Models.MyLearning;
+ using LearningHub.Nhs.Models.Report.ReportCreate;
+ using LearningHub.Nhs.OpenApi.Services.Interface.HttpClients;
+ using LearningHub.Nhs.OpenApi.Services.Interface.Services;
+ using Microsoft.Extensions.Logging;
+ using Newtonsoft.Json;
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Net;
+ using System.Net.Http;
+ using System.Text;
+ using System.Text.Json;
+ using System.Threading.Tasks;
+ using LearningHub.Nhs.OpenApi.Services.Helpers;
+ using System.Net.Http.Json;
+ using static System.Net.WebRequestMethods;
+ using IdentityModel.Client;
+ using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
+
+ ///
+ /// MoodleBridgeApiService.
+ ///
+ public class MoodleBridgeApiService : IMoodleBridgeApiService
+ {
+ private readonly IMoodleBridgeHttpClient moodleBridgeHttpClient;
+ private readonly ILogger logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// moodleHttpClient.
+ /// logger.
+ public MoodleBridgeApiService(IMoodleBridgeHttpClient moodleBridgeHttpClient, ILogger logger)
+ {
+ this.moodleBridgeHttpClient = moodleBridgeHttpClient;
+ this.logger = logger;
+ }
+
+ ///
+ /// GetUserInstancesByEmailAsync.
+ ///
+ /// The email.
+ /// UserId from Moodle.
+ public async Task GetUserInstancesByEmail(string email)
+ {
+ MoodleUserIdsResponseModel viewmodel = null;
+
+ try
+ {
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var request = $"/api/v1/Users/{Uri.EscapeDataString(email)}/instance-ids";
+ var response = await client.GetAsync(request).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = await response.Content.ReadAsStringAsync();
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ viewmodel = System.Text.Json.JsonSerializer.Deserialize(result, options);
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ if (viewmodel?.MoodleUserIds != null)
+ {
+ return MoodleInstanceUsersHelper.BuildUserIdsByInstance(viewmodel.MoodleUserIds);
+ }
+ else
+ {
+ throw new Exception("Failed to retrieve Moodle user IDs.");
+ }
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "An error occurred while fetching user instances by email.");
+ throw;
+ }
+ }
+
+ ///
+ /// GetEnrolledCoursesAsync.
+ ///
+ /// Moodle instances user id.
+ /// MyLearningRequestModel.
+ /// The months.
+ /// A representing the result of the asynchronous operation.
+ public async Task GetRecentEnrolledCoursesAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, MyLearningRequestModel requestModel, int? month = null)
+ {
+ try
+ {
+ if (moodleUserInstanceUserIds?.MoodleInstanceUserIds == null ||
+ !moodleUserInstanceUserIds.MoodleInstanceUserIds.Any())
+ {
+ throw new ArgumentException("UserIds are required.");
+ }
+
+ string statusFilter = string.Empty; ;
+
+ if ((requestModel.Incomplete && requestModel.Complete) || (!requestModel.Incomplete && !requestModel.Complete))
+ {
+ statusFilter = string.Empty; ;
+ }
+ else if (requestModel.Incomplete)
+ {
+ statusFilter = "inprogress";
+ }
+ else
+ {
+ statusFilter = "completed";
+ }
+
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var queryParams = new List();
+
+ if (!string.IsNullOrWhiteSpace(statusFilter))
+ queryParams.Add($"statusfilter={statusFilter}");
+
+ if (month.HasValue)
+ queryParams.Add($"months={month.Value}");
+
+ if (!string.IsNullOrWhiteSpace(requestModel?.SearchText))
+ {
+ queryParams.Add($"search={Uri.EscapeDataString(requestModel.SearchText)}");
+ }
+
+ var queryString = queryParams.Any()
+ ? "?" + string.Join("&", queryParams)
+ : string.Empty;
+
+
+ var requestUri = $"api/v1/users/recent-courses{queryString}";
+
+ var response = await client.PostAsJsonAsync(
+ requestUri,
+ moodleUserInstanceUserIds).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ var result = System.Text.Json.JsonSerializer.Deserialize(json, options);
+
+ return result ?? new MoodleCompletionsApiResponseModel();
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ throw new Exception($"Request failed with status code {response.StatusCode}");
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "An error occurred while fetching user's recent learning activities ");
+ throw;
+ }
+ }
+
+ ///
+ /// GetEnrolledCoursesAsync.
+ ///
+ /// Moodle Instances user id.
+ /// MyLearningRequestModel requestModel.
+ /// A representing the result of the asynchronous operation.
+ public async Task GetEnrolledCoursesHistoryAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, MyLearningRequestModel requestModel)
+ {
+ try
+ {
+ if (moodleUserInstanceUserIds?.MoodleInstanceUserIds == null ||
+ !moodleUserInstanceUserIds.MoodleInstanceUserIds.Any())
+ {
+ throw new ArgumentException("UserIds are required.");
+ }
+
+ string statusFilter = string.Empty; ;
+
+ if ((requestModel.Incomplete && requestModel.Complete) || (!requestModel.Incomplete && !requestModel.Complete))
+ {
+ statusFilter = string.Empty;
+ }
+ else if (requestModel.Incomplete)
+ {
+ statusFilter = "inprogress";
+ }
+ else
+ {
+ statusFilter = "completed";
+ }
+
+ var client = await this.moodleBridgeHttpClient.GetClient();
+ // Build query string (optional params)
+ var queryParams = new List();
+ queryParams.Add($"months=0");
+ if (!string.IsNullOrWhiteSpace(statusFilter))
+ queryParams.Add($"statusfilter={statusFilter}");
+
+ if (!string.IsNullOrWhiteSpace(requestModel?.SearchText))
+ {
+ queryParams.Add($"search={Uri.EscapeDataString(requestModel.SearchText)}");
+ }
+
+ var queryString = queryParams.Any()
+ ? "?" + string.Join("&", queryParams)
+ : string.Empty;
+
+ var requestUri = $"api/v1/users/recent-courses{queryString}";
+
+ var response = await client.PostAsJsonAsync(
+ requestUri,
+ moodleUserInstanceUserIds).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ var result = System.Text.Json.JsonSerializer.Deserialize(json, options);
+
+ return result ?? new MoodleCompletionsApiResponseModel();
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ throw new Exception($"Request failed with status code {response.StatusCode}");
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// GetInProgressEnrolledCoursesAsync.
+ ///
+ /// user email.
+ /// A representing the result of the asynchronous operation.
+ public async Task GetInProgressEnrolledCoursesAsync(string email)
+ {
+ try
+ {
+ var moodleUserInstanceUserIds = await this.GetUserInstancesByEmail(email);
+ if (moodleUserInstanceUserIds?.MoodleInstanceUserIds == null ||
+ !moodleUserInstanceUserIds.MoodleInstanceUserIds.Any())
+ {
+ throw new ArgumentException("UserIds are required.");
+ }
+
+ string statusFilter = "inprogress";
+
+ var client = await this.moodleBridgeHttpClient.GetClient();
+ // Build query string (optional params)
+ var queryParams = new List();
+ queryParams.Add($"months=0");
+ if (statusFilter != null)
+ queryParams.Add($"statusfilter={statusFilter}");
+
+ var queryString = queryParams.Any()
+ ? "?" + string.Join("&", queryParams)
+ : string.Empty;
+
+ var requestUri = $"api/v1/users/recent-courses{queryString}";
+
+ var response = await client.PostAsJsonAsync(
+ requestUri,
+ moodleUserInstanceUserIds).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ var result = System.Text.Json.JsonSerializer.Deserialize(json, options);
+
+ return result ?? new MoodleCompletionsApiResponseModel();
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ throw new Exception($"Request failed with status code {response.StatusCode}");
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// GetUserLearningHistory.
+ ///
+ /// user email.
+ /// The page Number.
+ /// A representing the result of the asynchronous operation.
+ public async Task GetUserCertificateAsync(string email, string filterText = "")
+ {
+ try
+ {
+ var moodleUserInstanceUserIds = await this.GetUserInstancesByEmail(email);
+ if (moodleUserInstanceUserIds?.MoodleInstanceUserIds == null ||
+ !moodleUserInstanceUserIds.MoodleInstanceUserIds.Any())
+ {
+ throw new ArgumentException("UserIds are required.");
+ }
+ var client = await this.moodleBridgeHttpClient.GetClient();
+ // Build query string (optional params)
+ var queryParams = new List();
+ if (!string.IsNullOrWhiteSpace(filterText))
+ {
+ queryParams.Add($"searchterm={Uri.EscapeDataString(filterText)}");
+ }
+
+ var queryString = queryParams.Any()
+ ? "?" + string.Join("&", queryParams)
+ : string.Empty;
+
+
+ var requestUri = $"api/v1/Users/certificates{queryString}";
+
+ var response = await client.PostAsJsonAsync(
+ requestUri,
+ moodleUserInstanceUserIds).ConfigureAwait(false);
+
+
+ if (response.IsSuccessStatusCode)
+ {
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ var result = await response.Content
+ .ReadFromJsonAsync(options)
+ .ConfigureAwait(false);
+
+ return result ?? new MoodleCertificateResponseModel();
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ throw new Exception($"Request failed with status code {response.StatusCode}");
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// GetUserCertificatefromMoodleInstancesAsync.
+ ///
+ /// moodleUserInstanceUserIds.
+ /// The page Number.
+ /// A representing the result of the asynchronous operation.
+ public async Task GetUserCertificateFromMoodleInstancesAsync(MoodleInstanceUserIdsViewModel moodleUserInstanceUserIds, string filterText = "")
+ {
+ try
+ {
+ if (moodleUserInstanceUserIds?.MoodleInstanceUserIds == null ||
+ !moodleUserInstanceUserIds.MoodleInstanceUserIds.Any())
+ {
+ throw new ArgumentException("UserIds are required.");
+ }
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var queryParams = new List();
+ if (!string.IsNullOrWhiteSpace(filterText))
+ {
+ queryParams.Add($"searchterm={Uri.EscapeDataString(filterText)}");
+ }
+
+ var queryString = queryParams.Any()
+ ? "?" + string.Join("&", queryParams)
+ : string.Empty;
+
+
+ var requestUri = $"api/v1/Users/certificates{queryString}";
+
+ var response = await client.PostAsJsonAsync(
+ requestUri,
+ moodleUserInstanceUserIds).ConfigureAwait(false);
+
+
+ if (response.IsSuccessStatusCode)
+ {
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ var result = await response.Content
+ .ReadFromJsonAsync(options)
+ .ConfigureAwait(false);
+
+ return result ?? new MoodleCertificateResponseModel();
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ throw new Exception($"Request failed with status code {response.StatusCode}");
+ }
+ catch (Exception ex)
+ {
+ return null;
+ }
+ }
+
+ ///
+ /// GetAllMoodleCategoriesAsync.
+ ///
+ /// A representing the result of the asynchronous operation.
+ public async Task> GetAllMoodleCategoriesAsync()
+ {
+ MoodleInstancesCategoriesResponseModel viewmodel = null;
+
+ try
+ {
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var request = $"/api/v1/Courses/categories";
+ var response = await client.GetAsync(request).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = response.Content.ReadAsStringAsync().Result;
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ viewmodel = System.Text.Json.JsonSerializer.Deserialize(result, options);
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ return viewmodel.Results;
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "An error occurred while fetching user instances by email.");
+ throw;
+ }
+ }
+
+ ///
+ /// GetCoursesByCategoryIdAsync.
+ ///
+ /// The categoryId.
+ ///
+ public async Task GetCoursesByCategoryIdAsync(string selectedcategoryId)
+ {
+ MoodleCourseResultsResponseModel viewmodel = null;
+ var (instanceName, categoryId) = selectedcategoryId.Split(':') is var p && p.Length == 2 ? (p[0], p[1]) : (null, null);
+
+ try
+ {
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var request = $"api/v1/Courses/search?value={Uri.EscapeDataString(categoryId.ToString())}" + $"&instance={Uri.EscapeDataString(instanceName)}";
+ var response = await client.GetAsync(request).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
+
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ viewmodel = System.Text.Json.JsonSerializer
+ .Deserialize(result, options);
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized ||
+ response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ return viewmodel ?? new MoodleCourseResultsResponseModel();
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "An error occurred while fetching Moodle categories.");
+ throw;
+ }
+ }
+
+ ///
+ /// GetSubCategoryByCategoryIdAsync.
+ ///
+ /// The categoryId.
+ ///
+ public async Task> GetSubCategoryByCategoryIdAsync(string selectedcategoryId)
+ {
+ MoodleInstanceSubCategoryResponseModel subcategories = null;
+ var (instanceName, categoryId) = selectedcategoryId.Split(':') is var p && p.Length == 2 ? (p[0], p[1]) : (null, null);
+
+ try
+ {
+ var client = await this.moodleBridgeHttpClient.GetClient();
+
+ var request = $"api/v1/Courses/{categoryId}/subcategories?{instanceName}";
+ var response = await client.GetAsync(request).ConfigureAwait(false);
+
+ if (response.IsSuccessStatusCode)
+ {
+ var result = response.Content.ReadAsStringAsync().Result;
+ var options = new JsonSerializerOptions
+ {
+ PropertyNameCaseInsensitive = true,
+ };
+
+ subcategories = System.Text.Json.JsonSerializer.Deserialize(result, options);
+ }
+ else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
+ {
+ throw new Exception("AccessDenied");
+ }
+
+ return subcategories.Results;
+ }
+ catch (Exception ex)
+ {
+ this.logger.LogError(ex, "An error occurred while fetching sub categories by category id.");
+ throw;
+ }
+ }
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MyLearningService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MyLearningService.cs
index d9c124b89..12d9e42cd 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MyLearningService.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MyLearningService.cs
@@ -12,8 +12,10 @@
using LearningHub.Nhs.Models.Entities.Activity;
using LearningHub.Nhs.Models.Entities.Resource;
using LearningHub.Nhs.Models.Enums;
+ using LearningHub.Nhs.Models.Moodle;
using LearningHub.Nhs.Models.Moodle.API;
using LearningHub.Nhs.Models.MyLearning;
+ using LearningHub.Nhs.Models.Resource.AzureMediaAsset;
using LearningHub.Nhs.OpenApi.Models.Configuration;
using LearningHub.Nhs.OpenApi.Repositories.Helpers;
using LearningHub.Nhs.OpenApi.Repositories.Interface.Repositories;
@@ -75,6 +77,11 @@ public class MyLearningService : IMyLearningService
///
private readonly IMoodleApiService moodleApiService;
+ ///
+ /// The moodleBridgeApiService.
+ ///
+ private readonly IMoodleBridgeApiService moodleBridgeApiService;
+
///
/// The mapper.
///
@@ -99,6 +106,7 @@ public class MyLearningService : IMyLearningService
/// The mediaResourceActivity.
/// The resourceActivity
/// The moodleApiService.
+ /// The moodleBridgeApiService.
public MyLearningService(
IResourceActivityRepository resourceActivityRepository,
IMediaResourcePlayedSegmentRepository mediaResourcePlayedSegmentRepository,
@@ -110,7 +118,8 @@ public MyLearningService(
IScormActivityRepository scormActivityRepository,
IMediaResourceActivityRepository mediaResourceActivity,
IResourceRepository resourceRepository,
- IMoodleApiService moodleApiService)
+ IMoodleApiService moodleApiService,
+ IMoodleBridgeApiService moodleBridgeApiService)
{
this.resourceActivityRepository = resourceActivityRepository;
this.mediaResourcePlayedSegmentRepository = mediaResourcePlayedSegmentRepository;
@@ -123,6 +132,7 @@ public MyLearningService(
this.mediaResourceActivity = mediaResourceActivity;
this.resourceRepository = resourceRepository;
this.moodleApiService = moodleApiService;
+ this.moodleBridgeApiService = moodleBridgeApiService;
}
///
@@ -155,13 +165,12 @@ public async Task GetActivityDetailed(int userId, M
/// /// The user id.
/// The request model.
/// The .
- public async Task GetUserRecentMyLearningActivitiesAsync(int userId, MyLearningRequestModel requestModel)
+ public async Task GetUserRecentMyLearningActivitiesAsync(int userId, MyLearningApiRequestViewModel requestModel)
{
try
{
- var result = await resourceActivityRepository.GetUserRecentMyLearningActivities(userId, requestModel);
-
- var entrolledCourses = await this.moodleApiService.GetRecentEnrolledCoursesAsync(userId, requestModel, 6);
+ var result = await resourceActivityRepository.GetUserRecentMyLearningActivities(userId, requestModel.Request);
+ var entrolledCourses = await this.moodleBridgeApiService.GetRecentEnrolledCoursesAsync(requestModel.MoodleInstanceUserIds, requestModel.Request, 6);
List mappedMyLearningActivities = new();
List mappedEnrolledCourses = new();
List combainedUserActivities = new();
@@ -208,43 +217,46 @@ public async Task GetUserRecentMyLearning
if (entrolledCourses != null)
{
- mappedEnrolledCourses = entrolledCourses.Select(course => new MyLearningCombinedActivitiesViewModel
- {
- UserId = userId,
- ResourceId = (int)course.Id,
- ResourceVersionId = (int)course.Id,
- IsCurrentResourceVersion = true,
- ResourceReferenceId = (int)course.Id,
- MajorVersion = 1,
- MinorVersion = 0,
- ResourceType = ResourceTypeEnum.Moodle,
- Title = course.DisplayName,
- CertificateEnabled = course.CertificateEnabled,
- ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
- ActivityDate = course.LastAccessDate.HasValue
- ? DateTimeOffset.FromUnixTimeSeconds(course.LastAccessDate.Value)
- : DateTimeOffset.MinValue,
- ScorePercentage = Convert.ToInt32(course.ProgressPercentage.TrimEnd('%')),
- TotalActivities = course.TotalActivities,
- CompletedActivities = course.CompletedActivities,
- IsMostRecent = false,
- ResourceDurationMilliseconds = 0,
- CompletionPercentage = 0,
- ProvidersJson = null,
- AssessmentPassMark = 0,
- AssessmentType = 0,
- AssesmentScore = 0,
- CertificateAwardedDate = course.EndDate.HasValue
- ? DateTimeOffset.FromUnixTimeSeconds(course.EndDate.Value)
- : DateTimeOffset.MinValue,
- }).ToList();
+ mappedEnrolledCourses = entrolledCourses?.Results?
+ .Where(r => r.Data?.Courses != null)
+ .SelectMany(r => r.Data.Courses)
+ .Select(course => new MyLearningCombinedActivitiesViewModel
+ {
+ UserId = userId,
+ ResourceId = (int)course.Id,
+ ResourceVersionId = (int)course.Id,
+ IsCurrentResourceVersion = true,
+ ResourceReferenceId = (int)course.Id,
+ MajorVersion = 1,
+ MinorVersion = 0,
+ ResourceType = ResourceTypeEnum.Moodle,
+ Title = course.DisplayName,
+ CertificateEnabled = course.CertificateEnabled,
+ ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
+ ActivityDate = course.LastAccessDate.HasValue
+ ? DateTimeOffset.FromUnixTimeSeconds(course.LastAccessDate.Value)
+ : DateTimeOffset.MinValue,
+ ScorePercentage = Convert.ToInt32(course.ProgressPercentage.TrimEnd('%')),
+ TotalActivities = course.TotalActivities,
+ CompletedActivities = course.CompletedActivities,
+ IsMostRecent = false,
+ ResourceDurationMilliseconds = 0,
+ CompletionPercentage = 0,
+ ProvidersJson = null,
+ AssessmentPassMark = 0,
+ AssessmentType = 0,
+ AssesmentScore = 0,
+ CertificateAwardedDate = course.EndDate.HasValue
+ ? DateTimeOffset.FromUnixTimeSeconds(course.EndDate.Value)
+ : DateTimeOffset.MinValue,
+ }).ToList();
}
// Combine both result sets
combainedUserActivities = mappedMyLearningActivities.Concat(mappedEnrolledCourses).ToList();
- var pagedResults = combainedUserActivities.OrderByDescending(activity => activity.ActivityDate).Skip(requestModel.Skip).Take(requestModel.Take).ToList();
+ var pagedResults = combainedUserActivities.OrderByDescending(activity => activity.ActivityDate).Skip(requestModel.Request.Skip).Take(requestModel.Request.Take).ToList();
// Count total records.
MyLearningActivitiesDetailedViewModel viewModel = new MyLearningActivitiesDetailedViewModel()
@@ -268,29 +280,29 @@ public async Task GetUserRecentMyLearning
/// /// The user id.
/// The request model.
/// The .
- public async Task GetUserLearningHistoryAsync(int userId, MyLearningRequestModel requestModel)
+ public async Task GetUserLearningHistoryAsync(int userId, MyLearningApiRequestViewModel requestModel)
{
try
{
- (string strActivityStatus, bool activityStatusEnumFlag) = resourceActivityRepository.GetActivityStatusFilter(requestModel);
- (string strResourceTypes, bool resourceTypeFlag) = resourceActivityRepository.ApplyResourceTypesfilters(requestModel);
+ (string strActivityStatus, bool activityStatusEnumFlag) = resourceActivityRepository.GetActivityStatusFilter(requestModel.Request);
+ (string strResourceTypes, bool resourceTypeFlag) = resourceActivityRepository.ApplyResourceTypesfilters(requestModel.Request);
var result = new List();
if (
- (!activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Courses) ||
- (activityStatusEnumFlag && resourceTypeFlag && !requestModel.Courses) ||
- (activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Courses) ||
- (!activityStatusEnumFlag && resourceTypeFlag && !requestModel.Courses) ||
- (!activityStatusEnumFlag && resourceTypeFlag && requestModel.Courses) ||
- (activityStatusEnumFlag && resourceTypeFlag && requestModel.Courses))
+ (!activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && resourceTypeFlag && !requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Request.Courses) ||
+ (!activityStatusEnumFlag && resourceTypeFlag && !requestModel.Request.Courses) ||
+ (!activityStatusEnumFlag && resourceTypeFlag && requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && resourceTypeFlag && requestModel.Request.Courses))
{
- if (requestModel.SearchText != null)
+ if (requestModel.Request.SearchText != null)
{
- result = await resourceActivityRepository.GetUserLearningHistoryBasedonSearchText(userId, requestModel);
+ result = await resourceActivityRepository.GetUserLearningHistoryBasedonSearchText(userId, requestModel.Request);
}
else
{
- result = await resourceActivityRepository.GetUserLearningHistory(userId, requestModel);
+ result = await resourceActivityRepository.GetUserLearningHistory(userId, requestModel.Request);
}
}
@@ -338,56 +350,60 @@ public async Task GetUserLearningHistoryA
}).ToList();
}
- List entrolledCourses = new();
+ MoodleCompletionsApiResponseModel entrolledCourses = new();
if (
- (!activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Courses) ||
- (!activityStatusEnumFlag && !resourceTypeFlag && requestModel.Courses) ||
- (!activityStatusEnumFlag && resourceTypeFlag && requestModel.Courses) ||
- (activityStatusEnumFlag && resourceTypeFlag && requestModel.Courses) ||
- (activityStatusEnumFlag && !resourceTypeFlag && requestModel.Courses) ||
- (activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Courses))
+ (!activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Request.Courses) ||
+ (!activityStatusEnumFlag && !resourceTypeFlag && requestModel.Request.Courses) ||
+ (!activityStatusEnumFlag && resourceTypeFlag && requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && resourceTypeFlag && requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && !resourceTypeFlag && requestModel.Request.Courses) ||
+ (activityStatusEnumFlag && !resourceTypeFlag && !requestModel.Request.Courses))
{
- entrolledCourses = await this.moodleApiService.GetEnrolledCoursesHistoryAsync(userId, requestModel);
+ ////entrolledCourses = await this.moodleApiService.GetEnrolledCoursesHistoryAsync(userId, requestModel.Request);
+ entrolledCourses = await this.moodleBridgeApiService.GetEnrolledCoursesHistoryAsync(requestModel.MoodleInstanceUserIds, requestModel.Request);
if (entrolledCourses != null)
{
- mappedEnrolledCourses = entrolledCourses.Select(course => new MyLearningCombinedActivitiesViewModel
- {
- UserId = userId,
- ResourceId = (int)course.Id,
- ResourceVersionId = (int)course.Id,
- IsCurrentResourceVersion = true,
- ResourceReferenceId = (int)course.Id,
- MajorVersion = 1,
- MinorVersion = 0,
- ResourceType = ResourceTypeEnum.Moodle,
- Title = course.DisplayName,
- CertificateEnabled = course.CertificateEnabled,
- ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
- ActivityDate = course.LastAccessDate.HasValue
+ mappedEnrolledCourses = entrolledCourses?.Results?
+ .Where(r => r.Data?.Courses != null)
+ .SelectMany(r => r.Data.Courses)
+ .Select(course => new MyLearningCombinedActivitiesViewModel
+ {
+ UserId = userId,
+ ResourceId = (int)course.Id,
+ ResourceVersionId = (int)course.Id,
+ IsCurrentResourceVersion = true,
+ ResourceReferenceId = (int)course.Id,
+ MajorVersion = 1,
+ MinorVersion = 0,
+ ResourceType = ResourceTypeEnum.Moodle,
+ Title = course.DisplayName,
+ CertificateEnabled = course.CertificateEnabled,
+ ActivityStatus = (course.Completed == true || course.ProgressPercentage.TrimEnd('%') == "100") ? ActivityStatusEnum.Completed : ActivityStatusEnum.Incomplete,
+ ActivityDate = course.LastAccessDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(course.LastAccessDate.Value)
: DateTimeOffset.MinValue,
- ScorePercentage = int.TryParse(course.ProgressPercentage.TrimEnd('%'), out var score) ? score : 0,
- TotalActivities = course.TotalActivities,
- CompletedActivities = course.CompletedActivities,
- IsMostRecent = false,
- ResourceDurationMilliseconds = 0,
- CompletionPercentage = 0,
- ProvidersJson = null,
- AssessmentPassMark = 0,
- AssessmentType = 0,
- AssesmentScore = 0,
- CertificateAwardedDate = course.EndDate.HasValue
+ ScorePercentage = int.TryParse(course.ProgressPercentage.TrimEnd('%'), out var score) ? score : 0,
+ TotalActivities = course.TotalActivities,
+ CompletedActivities = course.CompletedActivities,
+ IsMostRecent = false,
+ ResourceDurationMilliseconds = 0,
+ CompletionPercentage = 0,
+ ProvidersJson = null,
+ AssessmentPassMark = 0,
+ AssessmentType = 0,
+ AssesmentScore = 0,
+ CertificateAwardedDate = course.EndDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(course.EndDate.Value)
: DateTimeOffset.MinValue,
- }).ToList();
+ }).ToList();
}
}
// Combine both result sets
combainedUserActivities = mappedMyLearningActivities.Concat(mappedEnrolledCourses).ToList();
- var pagedResults = combainedUserActivities.OrderByDescending(activity => activity.ActivityDate).Skip(requestModel.Skip).Take(requestModel.Take).ToList();
+ var pagedResults = combainedUserActivities.OrderByDescending(activity => activity.ActivityDate).Skip(requestModel.Request.Skip).Take(requestModel.Request.Take).ToList();
// Count total records.
MyLearningActivitiesDetailedViewModel viewModel = new MyLearningActivitiesDetailedViewModel()
@@ -702,20 +718,19 @@ public async Task> PopulateMyLearningDetai
/// The user id.
/// The request model
/// The .
- public async Task GetUserCertificateDetails(int userId, MyLearningRequestModel requestModel)
+ public async Task GetUserCertificateDetails(int userId, MyLearningApiRequestViewModel requestModel)
{
- Task>? courseCertificatesTask = null;
- var filteredResource = GetFilteredResourceType(requestModel);
+ Task? courseCertificatesTask = null;
+ var filteredResource = GetFilteredResourceType(requestModel.Request);
- if (filteredResource.Count() == 0 || (filteredResource.Any() && requestModel.Courses))
+ if (filteredResource.Count() == 0 || (filteredResource.Any() && requestModel.Request.Courses))
{
- courseCertificatesTask = !string.IsNullOrWhiteSpace(requestModel.SearchText) ?
- moodleApiService.GetUserCertificateAsync(userId, requestModel.SearchText) : moodleApiService.GetUserCertificateAsync(userId);
-
+ courseCertificatesTask = !string.IsNullOrWhiteSpace(requestModel.Request.SearchText) ?
+ moodleBridgeApiService.GetUserCertificateFromMoodleInstancesAsync(requestModel.MoodleInstanceUserIds, requestModel.Request.SearchText) : moodleBridgeApiService.GetUserCertificateFromMoodleInstancesAsync(requestModel.MoodleInstanceUserIds);
}
- var resourceCertificatesTask = !string.IsNullOrWhiteSpace(requestModel.SearchText) ?
- resourceRepository.GetUserCertificateDetails(userId, requestModel.SearchText) : resourceRepository.GetUserCertificateDetails(userId);
+ var resourceCertificatesTask = !string.IsNullOrWhiteSpace(requestModel.Request.SearchText) ?
+ resourceRepository.GetUserCertificateDetails(userId, requestModel.Request.SearchText) : resourceRepository.GetUserCertificateDetails(userId);
// Await all active tasks in parallel
@@ -730,23 +745,24 @@ public async Task GetUserCertificateDet
if (courseCertificatesTask != null)
{
- var courseCertificates = courseCertificatesTask.Result ?? Enumerable.Empty();
-
- mappedCourseCertificates = courseCertificates.Select(c => new UserCertificateViewModel
- {
- Title = string.IsNullOrWhiteSpace(c.ResourceTitle) ? c.ResourceName : c.ResourceTitle,
- ResourceTypeId = (int)ResourceTypeEnum.Moodle,
- ResourceReferenceId = 0,
- MajorVersion = 0,
- MinorVersion = 0,
- AwardedDate = c.AwardedDate.HasValue
+ mappedCourseCertificates = courseCertificatesTask.Result?.Results?
+ .Where(r => r.Data?.Certificates != null)
+ .SelectMany(r => r.Data.Certificates)
+ .Select(c => new UserCertificateViewModel
+ {
+ Title = string.IsNullOrWhiteSpace(c.ResourceTitle) ? c.ResourceName : c.ResourceTitle,
+ ResourceTypeId = (int)ResourceTypeEnum.Moodle,
+ ResourceReferenceId = 0,
+ MajorVersion = 0,
+ MinorVersion = 0,
+ AwardedDate = c.AwardedDate.HasValue
? DateTimeOffset.FromUnixTimeSeconds(c.AwardedDate.Value)
: DateTimeOffset.MinValue,
- CertificatePreviewUrl = c.PreviewLink,
- CertificateDownloadUrl = c.DownloadLink,
- ResourceVersionId = 0,
- ProvidersJson = null,
- });
+ CertificatePreviewUrl = c.PreviewLink,
+ CertificateDownloadUrl = c.DownloadLink,
+ ResourceVersionId = 0,
+ ProvidersJson = null,
+ });
}
var allCertificates = resourceCertificates.Concat(mappedCourseCertificates);
@@ -764,8 +780,8 @@ public async Task GetUserCertificateDet
var totalCount = orderedCertificates.Count();
var pagedResults = orderedCertificates
- .Skip(requestModel.Skip)
- .Take(requestModel.Take)
+ .Skip(requestModel.Request.Skip)
+ .Take(requestModel.Request.Take)
.ToList();
return new MyLearningCertificatesDetailedViewModel
@@ -775,9 +791,6 @@ public async Task GetUserCertificateDet
};
}
-
-
-
private IQueryable ApplyFilters(IQueryable query, MyLearningRequestModel requestModel)
{
// Text filter - Title, Keywords or Description.
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Startup.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Startup.cs
index 73c887df7..1670bc090 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Startup.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Startup.cs
@@ -39,6 +39,7 @@ public static void AddServices(this IServiceCollection services, IConfiguration
}
services.AddHttpClient();
+ services.AddHttpClient();
services.AddScoped();
services.AddScoped();
services.AddScoped();
@@ -90,6 +91,7 @@ public static void AddServices(this IServiceCollection services, IConfiguration
services.AddScoped();
services.AddScoped();
services.AddScoped();
+ services.AddScoped();
services.AddScoped();
// Register IFindwiseApiFacade based on feature flag
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj b/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj
index 93461ce2b..27ab96576 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi.Tests/LearningHub.Nhs.OpenApi.Tests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Configuration/ConfigurationExtensions.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Configuration/ConfigurationExtensions.cs
index 309eb8bd5..07c0e431b 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Configuration/ConfigurationExtensions.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Configuration/ConfigurationExtensions.cs
@@ -46,10 +46,16 @@ public static class ConfigurationExtensions
public const string AzureSectionName = "Azure";
///
- /// The FindwiseSectionName.
+ /// The MoodleSectionName.
///
public const string MoodleSectionName = "Moodle";
+ ///
+ /// The MoodleBridgeSectionName.
+ ///
+ public const string MoodleBridgeSectionName = "MoodleBridgeAPIConfig";
+
+
///
/// The DatabricksSectionName.
///
@@ -83,6 +89,8 @@ public static void AddConfig(this IServiceCollection services, IConfiguration co
services.AddOptions().Bind(config.GetSection(MoodleSectionName));
+ services.AddOptions().Bind(config.GetSection(MoodleBridgeSectionName));
+
services.AddOptions().Bind(config.GetSection(DatabricksSectionName));
services.AddOptions().Bind(config.GetSection(FeatureFlagsSectionName));
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/CategoryController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/CategoryController.cs
index cc4b65562..f0e11089e 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/CategoryController.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/CategoryController.cs
@@ -19,16 +19,19 @@ public class CategoryController : OpenApiControllerBase
{
private readonly ICategoryService categoryService;
private readonly IMoodleApiService moodleApiService;
+ private readonly IMoodleBridgeApiService moodleBridgeApiService;
///
/// Initializes a new instance of the class.
///
/// The category service.
/// The moodleApi service.
- public CategoryController(ICategoryService categoryService, IMoodleApiService moodleApiService)
+ /// The moodle Bridge Api service.
+ public CategoryController(ICategoryService categoryService, IMoodleApiService moodleApiService, IMoodleBridgeApiService moodleBridgeApiService)
{
this.categoryService = categoryService;
this.moodleApiService = moodleApiService;
+ this.moodleBridgeApiService = moodleBridgeApiService;
}
///
@@ -51,9 +54,9 @@ public async Task GetCatalogueVersionCategory(int catalogueNodeVe
/// The catalogue.
[HttpGet]
[Route("GetCoursesByCategoryId/{categoryId}")]
- public async Task GetCoursesByCategoryId(int categoryId)
+ public async Task GetCoursesByCategoryId(string categoryId)
{
- var courses = await this.moodleApiService.GetCoursesByCategoryIdAsync(categoryId);
+ var courses = await this.moodleBridgeApiService.GetCoursesByCategoryIdAsync(categoryId);
return this.Ok(courses);
}
@@ -64,9 +67,9 @@ public async Task GetCoursesByCategoryId(int categoryId)
/// The catalogue.
[HttpGet]
[Route("GetSubCategoryByCategoryId/{categoryId}")]
- public async Task GetSubCategoryByCategoryId(int categoryId)
+ public async Task GetSubCategoryByCategoryId(string categoryId)
{
- var subCategories = await this.moodleApiService.GetSubCategoryByCategoryIdAsync(categoryId);
+ var subCategories = await this.moodleBridgeApiService.GetSubCategoryByCategoryIdAsync(categoryId);
return this.Ok(subCategories);
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/DashboardController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/DashboardController.cs
index 987904d94..6131a92ec 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/DashboardController.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/DashboardController.cs
@@ -1,6 +1,7 @@
namespace LearningHub.NHS.OpenAPI.Controllers
{
using System.Threading.Tasks;
+ using LearningHub.Nhs.Models.MyLearning;
using LearningHub.Nhs.OpenApi.Services.Interface.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -37,7 +38,7 @@ public DashboardController(IUserService userService, IDashboardService dashboard
[Route("resources/{dashboardType}/{pageNumber}")]
public async Task GetResources(string dashboardType, int pageNumber = 1)
{
- var response = await dashboardService.GetResources(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
+ var response = await this.dashboardService.GetResources(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
return this.Ok(response);
}
@@ -51,7 +52,7 @@ public async Task GetResources(string dashboardType, int pageNumbe
[Route("catalogues/{dashboardType}/{pageNumber}")]
public async Task GetCatalogues(string dashboardType, int pageNumber = 1)
{
- var response = await dashboardService.GetCatalogues(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
+ var response = await this.dashboardService.GetCatalogues(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
return this.Ok(response);
}
@@ -65,22 +66,20 @@ public async Task GetCatalogues(string dashboardType, int pageNum
[Route("myaccesslearning/{dashboardType}/{pageNumber}")]
public async Task GetMyAccessLearnings(string dashboardType, int pageNumber = 1)
{
- var response = await dashboardService.GetMyAccessLearnings(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
+ var response = await this.dashboardService.GetMyAccessLearnings(dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault());
return this.Ok(response);
}
///
/// Gets Catalogues.
///
- /// The dashboardTrayLearningResource type.
- /// The dashboard type.
- /// The page Number.
+ /// The GetMyCoursesAndElearningRequestModel.
/// IActionResult.
- [HttpGet]
- [Route("GetMyCoursesAndElearning/{dashboardTrayLearningResourceType}/{dashboardType}/{pageNumber}")]
- public async Task GetMyCoursesAndElearning(string dashboardTrayLearningResourceType, string dashboardType, int pageNumber = 1)
+ [HttpPost]
+ [Route("GetMyCoursesAndElearning")]
+ public async Task GetMyCoursesAndElearning([FromBody] GetMyCoursesAndElearningRequestModel request)
{
- var response = await dashboardService.GetMyCoursesAndElearning(dashboardTrayLearningResourceType, dashboardType, pageNumber, this.CurrentUserId.GetValueOrDefault(), "All");
+ var response = await this.dashboardService.GetMyCoursesAndElearning(request, this.CurrentUserId.GetValueOrDefault(), "All");
return this.Ok(response);
}
}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleBridgeController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleBridgeController.cs
new file mode 100644
index 000000000..f7a0e11d2
--- /dev/null
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleBridgeController.cs
@@ -0,0 +1,52 @@
+namespace LearningHub.NHS.OpenAPI.Controllers
+{
+ using Microsoft.AspNetCore.Authorization;
+ using Microsoft.AspNetCore.Mvc;
+ using System.Threading.Tasks;
+ using LearningHub.Nhs.OpenApi.Services.Interface.Services;
+
+ ///
+ /// Moodle Bridge operations.
+ ///
+ [Route("MoodleBridge")]
+ [ApiController]
+ [Authorize]
+ public class MoodleBridgeController : Controller
+ {
+ private readonly IMoodleBridgeApiService moodleBridgeApiService;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The moodle bridge service.
+ public MoodleBridgeController(IMoodleBridgeApiService moodleBridgeApiService)
+ {
+ this.moodleBridgeApiService = moodleBridgeApiService;
+ }
+
+ ///
+ /// The GetMoodle Instances UserIds.
+ ///
+ /// The LH user email.
+ /// The .
+ [HttpGet]
+ [Route("GetUserInstancesByEmail/{email}")]
+ public async Task GetUserInstancesByEmail(string email)
+ {
+ var moodleUser = await this.moodleBridgeApiService.GetUserInstancesByEmail(email);
+ return this.Ok(moodleUser);
+ }
+
+ ///
+ /// GetAllMoodleCategoriesAsync.
+ ///
+ /// A representing the result of the asynchronous operation.
+ [HttpGet]
+ [Route("GetAllMoodleCategories")]
+ public async Task GetAllMoodleCategoriesAsync()
+ {
+ var moodleCategories = await this.moodleBridgeApiService.GetAllMoodleCategoriesAsync();
+ return this.Ok(moodleCategories);
+ }
+ }
+}
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MyLearningController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MyLearningController.cs
index 4763f21cc..fbd05a867 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MyLearningController.cs
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MyLearningController.cs
@@ -59,7 +59,7 @@ public async Task GetActivityDetailed([FromBody] MyLearningReques
/// The .
[HttpPost]
[Route("GetUserRecentMyLearningActivities")]
- public async Task GetUserRecentMyLearningActivities([FromBody] MyLearningRequestModel requestModel)
+ public async Task GetUserRecentMyLearningActivities([FromBody] MyLearningApiRequestViewModel requestModel)
{
var activityModel = await this.myLearningService.GetUserRecentMyLearningActivitiesAsync(this.CurrentUserId.GetValueOrDefault(), requestModel);
return this.Ok(activityModel);
@@ -72,7 +72,7 @@ public async Task GetUserRecentMyLearningActivities([FromBody] My
/// The .
[HttpPost]
[Route("GetUserLearningHistory")]
- public async Task GetUserLearningHistory([FromBody] MyLearningRequestModel requestModel)
+ public async Task GetUserLearningHistory([FromBody] MyLearningApiRequestViewModel requestModel)
{
var activityModel = await this.myLearningService.GetUserLearningHistoryAsync(this.CurrentUserId.GetValueOrDefault(), requestModel);
return this.Ok(activityModel);
@@ -118,7 +118,7 @@ public async Task GetResourceCertificateDetails(int resourceRefer
/// A representing the result of the asynchronous operation.
[HttpPost]
[Route("GetUserCertificateDetails")]
- public async Task GetUserCertificateDetails([FromBody] MyLearningRequestModel requestModel)
+ public async Task GetUserCertificateDetails([FromBody] MyLearningApiRequestViewModel requestModel)
{
var certificateDetails = await this.myLearningService.GetUserCertificateDetails(this.CurrentUserId.GetValueOrDefault(), requestModel);
return this.Ok(certificateDetails);
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
index de5b7a6d7..57eb26f4f 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/LearningHub.NHS.OpenAPI.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
index 42b84d3b8..3a96c27b9 100644
--- a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
+++ b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json
@@ -156,6 +156,10 @@
"ApiWsRestFormat": "json",
"ApiWsToken": ""
},
+ "MoodleBridgeAPIConfig": {
+ "BaseUrl": "",
+ "Token": ""
+ },
"Databricks": {
"InstanceUrl": "",
"Token": "",
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
index 2a259d6b2..79f6af7f9 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services.Interface/LearningHub.Nhs.ReportApi.Services.Interface.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
index aebb8bb75..c8ca7a2ae 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services.UnitTests/LearningHub.Nhs.ReportApi.Services.UnitTests.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
index acfb75739..89bca5ef2 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Services/LearningHub.Nhs.ReportApi.Services.csproj
@@ -19,7 +19,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj b/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
index 9d86c24a0..ae1444ed9 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi.Shared/LearningHub.Nhs.ReportApi.Shared.csproj
@@ -17,7 +17,7 @@
-
+
diff --git a/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj b/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
index f31ff35e5..c19afef98 100644
--- a/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
+++ b/ReportAPI/LearningHub.Nhs.ReportApi/LearningHub.Nhs.ReportApi.csproj
@@ -20,7 +20,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
index 3a7660599..0462105ff 100644
--- a/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
+++ b/WebAPI/LearningHub.Nhs.API/LearningHub.Nhs.Api.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
index e1b7896b8..8d695c492 100644
--- a/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
+++ b/WebAPI/LearningHub.Nhs.Api.Shared/LearningHub.Nhs.Api.Shared.csproj
@@ -9,7 +9,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
index 4acbd2e13..100e6600d 100644
--- a/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
+++ b/WebAPI/LearningHub.Nhs.Api.UnitTests/LearningHub.Nhs.Api.UnitTests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Hierarchy/CatalogueNodeVersionCategoryCreate.sql b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Hierarchy/CatalogueNodeVersionCategoryCreate.sql
index cd0fa408f..9818d8f75 100644
--- a/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Hierarchy/CatalogueNodeVersionCategoryCreate.sql
+++ b/WebAPI/LearningHub.Nhs.Database/Stored Procedures/Hierarchy/CatalogueNodeVersionCategoryCreate.sql
@@ -6,12 +6,14 @@
-- Modification History
--
-- 14-10-2025 SA Initial Revision.
+-- 11-03-2026 SA Added instance name
-------------------------------------------------------------------------------
CREATE PROCEDURE [hierarchy].[CatalogueNodeVersionCategoryCreate]
(
@userId INT,
@CatalogueNodeVersionId INT,
- @CategoryId INT,
+ @categoryId INT,
+ @instanceName VARCHAR(50),
@UserTimezoneOffset int = NULL
)
@@ -33,19 +35,21 @@ BEGIN
END
INSERT INTO [hierarchy].[CatalogueNodeVersionCategory]
- ([CatalogueNodeVersionId]
- ,[CategoryId]
- ,[Deleted]
- ,[CreateUserId]
- ,[CreateDate]
- ,[AmendUserId]
- ,[AmendDate])
- VALUES
- (@CatalogueNodeVersionId
- ,@CategoryId
- ,0
- ,@userId
- ,@AmendDate
- ,@userId
- ,@AmendDate)
+ ([CatalogueNodeVersionId]
+ ,[CategoryId]
+ ,[InstanceName]
+ ,[Deleted]
+ ,[CreateUserId]
+ ,[CreateDate]
+ ,[AmendUserId]
+ ,[AmendDate])
+ VALUES
+ (@CatalogueNodeVersionId
+ ,@categoryId
+ ,@instanceName
+ ,0
+ ,@userId
+ ,@AmendDate
+ ,@userId
+ ,@AmendDate)
END
\ No newline at end of file
diff --git a/WebAPI/LearningHub.Nhs.Database/Tables/Hierarchy/CatalogueNodeVersionCategory.sql b/WebAPI/LearningHub.Nhs.Database/Tables/Hierarchy/CatalogueNodeVersionCategory.sql
index c3ddc4832..b5c9f3f15 100644
--- a/WebAPI/LearningHub.Nhs.Database/Tables/Hierarchy/CatalogueNodeVersionCategory.sql
+++ b/WebAPI/LearningHub.Nhs.Database/Tables/Hierarchy/CatalogueNodeVersionCategory.sql
@@ -2,6 +2,7 @@
[Id] [int] IDENTITY(1,1) NOT NULL,
[CatalogueNodeVersionId] [int] NOT NULL,
[CategoryId] [int] NOT NULL,
+ [InstanceName] [varchar](50) NULL,
[Deleted] [bit] NOT NULL,
[CreateUserId] [int] NOT NULL,
[CreateDate] [datetimeoffset](7) NOT NULL,
diff --git a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
index 5d12c4600..8273e219f 100644
--- a/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
+++ b/WebAPI/LearningHub.Nhs.Repository.Interface/LearningHub.Nhs.Repository.Interface.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
index b7cca29dc..a2628d76c 100644
--- a/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
+++ b/WebAPI/LearningHub.Nhs.Repository/LearningHub.Nhs.Repository.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
index 6ee630341..73e99b72e 100644
--- a/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
+++ b/WebAPI/LearningHub.Nhs.Services.Interface/LearningHub.Nhs.Services.Interface.csproj
@@ -16,7 +16,7 @@
-
+
all
diff --git a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
index dbb1f6a30..6b02d693a 100644
--- a/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
+++ b/WebAPI/LearningHub.Nhs.Services.UnitTests/LearningHub.Nhs.Services.UnitTests.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
index 98cec165a..d27db0e89 100644
--- a/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
+++ b/WebAPI/LearningHub.Nhs.Services/LearningHub.Nhs.Services.csproj
@@ -13,7 +13,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
index 3a2cb8961..1a8367ea1 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.ConsoleApp/LearningHub.Nhs.Migration.ConsoleApp.csproj
@@ -25,7 +25,7 @@
-
+
all
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
index b275eae94..56c3518c1 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Interface/LearningHub.Nhs.Migration.Interface.csproj
@@ -9,7 +9,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
index a18eb4196..e4a707d63 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Models/LearningHub.Nhs.Migration.Models.csproj
@@ -10,7 +10,7 @@
-
+
all
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
index bb23ca661..a6d13b605 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.Staging.Repository/LearningHub.Nhs.Migration.Staging.Repository.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
index 82a9b4aa6..2e25b373f 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration.UnitTests/LearningHub.Nhs.Migration.UnitTests.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
index de745363e..e21f1b8e1 100644
--- a/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
+++ b/WebAPI/MigrationTool/LearningHub.Nhs.Migration/LearningHub.Nhs.Migration.csproj
@@ -12,7 +12,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive