Skip to content
Open

TEST #1530

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
d088e34
Merge pull request #1301 from TechnologyEnhancedLearning/RC
AnjuJose011 Aug 5, 2025
72d5550
Merge pull request #1334 from TechnologyEnhancedLearning/RC
AnjuJose011 Aug 18, 2025
cdd53c5
TD-6116 Workflow and Nuget update
Phil-NHS Sep 3, 2025
eafe61b
Merge pull request #1377 from TechnologyEnhancedLearning/Develop/Feat…
Phil-NHS Sep 4, 2025
4d1a513
TD-6159 update
OluwatobiAwe Sep 29, 2025
ebead60
updated user profile table
OluwatobiAwe Oct 1, 2025
fb91066
TD-6159 update
OluwatobiAwe Sep 29, 2025
1595b36
updated user profile table
OluwatobiAwe Oct 1, 2025
8af1ef3
Merge pull request #1455 from TechnologyEnhancedLearning/Develop/Feat…
OluwatobiAwe Oct 1, 2025
6f7910f
TD-6159 removed elfh.externalsystem
OluwatobiAwe Oct 7, 2025
8631f42
TD-6159 database update
OluwatobiAwe Oct 10, 2025
e37a067
conflicts resloved
AnjuJose011 Oct 13, 2025
5bb4378
Merge pull request #1484 from TechnologyEnhancedLearning/MergeRC-CI
AnjuJose011 Oct 13, 2025
1bbec3d
Merge branch 'CI' into Develop/Features/TD-6159
OluwatobiAwe Oct 14, 2025
12360a6
.
OluwatobiAwe Oct 14, 2025
cf1d239
Post deployment script update
OluwatobiAwe Oct 14, 2025
c3719d0
removal of external system
OluwatobiAwe Oct 14, 2025
6b463ef
TD-6356-textdescription
AnjuJose011 Oct 23, 2025
e189d9c
Merge pull request #1494 from TechnologyEnhancedLearning/td-6356-Remo…
AnjuJose011 Oct 28, 2025
fe232b6
TD-6272 & TD-5906: Show Courses within a Catalogue
swapnamol-abraham Oct 28, 2025
6f2f369
Added Moodle configuration values
swapnamol-abraham Oct 28, 2025
72a79a9
Merge pull request #1504 from TechnologyEnhancedLearning/Develop/Feat…
swapnamol-abraham Oct 28, 2025
d75de66
Update LearningHub.Nhs.WebUI.AutomatedUiTests.csproj
AnjuJose011 Oct 29, 2025
488dcc1
converted GetUserByOpenAthensId ef query to SP
OluwatobiAwe Oct 31, 2025
8aff361
.
OluwatobiAwe Oct 31, 2025
aa0336c
Merge branch 'RC' into Develop/Features/TD-6159
OluwatobiAwe Nov 3, 2025
e2b8258
Implemented character indentation in the dropdown list.
swapnamol-abraham Nov 3, 2025
67c9453
Merge pull request #1508 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 3, 2025
6150abf
Corrected the url
swapnamol-abraham Nov 3, 2025
d58d920
Merge pull request #1509 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 3, 2025
c077b99
Corrected the Catalogue Id
swapnamol-abraham Nov 3, 2025
6d54e61
Merge pull request #1510 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 3, 2025
5f79b08
Merge pull request #1507 from TechnologyEnhancedLearning/Develop/Feat…
AnjuJose011 Nov 3, 2025
f3fd8f0
Fixes
AnjuJose011 Nov 3, 2025
9578063
Update MoodleApiService.cs
AnjuJose011 Nov 5, 2025
353c0ec
SIT fixes on the ticket TD-5906 & TD-6272
swapnamol-abraham Nov 5, 2025
af6f0ae
Merge pull request #1517 from TechnologyEnhancedLearning/Develop/Fixe…
swapnamol-abraham Nov 5, 2025
a3ce679
TD-6148: Neew stored procedures and DB types for ELFH-LH data sync
Nov 5, 2025
f9a5817
Merge branch 'RC' into Develop/Features/TD-6148-Create-a-PoC-mechanis…
sarathlal-sarangadharan Nov 5, 2025
8cfab1e
Merge pull request #1518 from TechnologyEnhancedLearning/Develop/Feat…
sarathlal-sarangadharan Nov 5, 2025
fd98d6b
LMS Error Occurring in Test Environment While Launching SCORM Content
swapnamol-abraham Nov 5, 2025
c3c664f
Merge pull request #1519 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 5, 2025
353ea38
Merge pull request #1516 from TechnologyEnhancedLearning/TD-6336-Enab…
AnjuJose011 Nov 5, 2025
cc333c1
TD-6272: SIT fixes
swapnamol-abraham Nov 6, 2025
6f468b8
Merge pull request #1520 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 6, 2025
4c9d5bf
SIT fixes
swapnamol-abraham Nov 6, 2025
9cbc0c1
Merge pull request #1521 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 6, 2025
39ad0d1
SIT fix
swapnamol-abraham Nov 6, 2025
c317da6
Merge pull request #1522 from TechnologyEnhancedLearning/Develop/Fixe…
swapnamol-abraham Nov 7, 2025
4a7f9f8
SIT fixes
swapnamol-abraham Nov 7, 2025
118a5a7
Merge pull request #1524 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 7, 2025
49e9db5
TD-6148: adf sync time update table has been moved to LH from eLfH
Nov 17, 2025
d724948
Merge pull request #1528 from TechnologyEnhancedLearning/Develop/Feat…
AnjuJose011 Nov 17, 2025
57718f8
Update TD-6148-ADFtableData.sql
AnjuJose011 Nov 17, 2025
ceda948
TD-6473 : Unable to view "action required" resources
swapnamol-abraham Nov 17, 2025
7611564
Merge pull request #1529 from TechnologyEnhancedLearning/Develop/Fixe…
AnjuJose011 Nov 17, 2025
b7040f4
Revert "TD-6473 : Unable to view "action required" resources"
AnjuJose011 Nov 18, 2025
a7d697e
Merge pull request #1543 from TechnologyEnhancedLearning/revert-1529-…
AnjuJose011 Nov 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions AdminUI/LearningHub.Nhs.AdminUI/Configuration/MoodleApiConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
namespace LearningHub.Nhs.AdminUI.Configuration
{
/// <summary>
/// The Moodle Settings.
/// </summary>
public class MoodleApiConfig
{
/// <summary>
/// Gets or sets the base url for the Moodle service.
/// </summary>
public string BaseUrl { get; set; } = null!;

/// <summary>
/// Gets or sets the Web service Rest Format.
/// </summary>
public string MoodleWSRestFormat { get; set; } = null!;

/// <summary>
/// Gets or sets the token.
/// </summary>
public string WSToken { get; set; } = null!;

/// <summary>
/// Gets or sets the token.
/// </summary>
public string ApiPath { get; set; } = "webservice/rest/server.php";

/// <summary>
/// Gets or sets the token.
/// </summary>
public string CoursePath { get; set; } = "course/view.php";
}
}
158 changes: 149 additions & 9 deletions AdminUI/LearningHub.Nhs.AdminUI/Controllers/CatalogueController.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
namespace LearningHub.Nhs.AdminUI.Controllers
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Drawing;
using System.Linq;
using System.Net.Mail;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using LearningHub.Nhs.AdminUI.Configuration;
using LearningHub.Nhs.AdminUI.Extensions;
using LearningHub.Nhs.AdminUI.Interfaces;
using LearningHub.Nhs.AdminUI.Models;
using LearningHub.Nhs.Models.Catalogue;
using LearningHub.Nhs.Models.Common;
using LearningHub.Nhs.Models.Common.Enums;
using LearningHub.Nhs.Models.Moodle;
using LearningHub.Nhs.Models.Paging;
using LearningHub.Nhs.Models.Resource;
using LearningHub.Nhs.Models.User;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

/// <summary>
/// Defines the <see cref="CatalogueController" />.
Expand Down Expand Up @@ -65,6 +65,11 @@ public class CatalogueController : BaseController
/// </summary>
private readonly IProviderService providerService;

/// <summary>
/// Defines the moodleApiService.
/// </summary>
private readonly IMoodleApiService moodleApiService;

/// <summary>
/// Defines the _settings.
/// </summary>
Expand Down Expand Up @@ -98,6 +103,7 @@ public class CatalogueController : BaseController
/// <param name="userGroupService">The userService<see cref="IUserGroupService"/>.</param>
/// <param name="fileService">The fileService<see cref="IFileService"/>.</param>
/// <param name="providerService">The providerService<see cref="IProviderService"/>.</param>
/// <param name="moodleApiService">The moodleApiService<see cref="IMoodleApiService"/>.</param>
/// <param name="logger">The logger<see cref="ILogger{LogController}"/>.</param>
/// <param name="options">The options<see cref="IOptions{WebSettings}"/>.</param>
/// <param name="websettings">The websettings<see cref="IOptions{WebSettings}"/>.</param>
Expand All @@ -107,6 +113,7 @@ public CatalogueController(
IUserGroupService userGroupService,
IFileService fileService,
IProviderService providerService,
IMoodleApiService moodleApiService,
ILogger<LogController> logger,
IOptions<WebSettings> options,
IOptions<WebSettings> websettings)
Expand All @@ -116,6 +123,7 @@ public CatalogueController(
this.userGroupService = userGroupService;
this.fileService = fileService;
this.providerService = providerService;
this.moodleApiService = moodleApiService;
this.logger = logger;
this.websettings = websettings;
this.settings = options.Value;
Expand Down Expand Up @@ -254,6 +262,38 @@ public async Task<IActionResult> CatalogueOwner(int id)
return this.View(vm);
}

/// <summary>
/// The CatalogueOwner.
/// </summary>
/// <param name="id">The id<see cref="int"/>.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[HttpGet]
[Route("MoodleCategory/{id}")]
public async Task<IActionResult> MoodleCategory(int id)
{
var vm = await this.catalogueService.GetCatalogueAsync(id);
if (vm == null)
{
return this.RedirectToAction("Error");
}

var categories = await this.moodleApiService.GetAllMoodleCategoriesAsync();

vm.MoodleCategories = categories;

// Build hierarchical select list
var selectList = BuildList(categories, parentId: null, depth: 0);
foreach (var item in selectList)
{
item.Text = WebUtility.HtmlDecode(item.Text);
}
vm.MoodleCategorySelectList = new SelectList(selectList, "Value", "Text");
this.ViewData["CatalogueName"] = vm.Name;
this.ViewData["id"] = id;

return this.View(vm);
}

/// <summary>
/// The UserGroups.
/// </summary>
Expand Down Expand Up @@ -678,6 +718,77 @@ public async Task<IActionResult> AddUserGroupsToCatalogue(int catalogueNodeId, i
}
}

/// <summary>
/// The AddCategoryToCatalogue.
/// </summary>
/// <param name="catalogueViewModel">The catalogueViewModel<see cref="CatalogueViewModel"/>.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[HttpPost]
[Route("AddCategoryToCatalogue")]
public async Task<IActionResult> AddCategoryToCatalogue(CatalogueViewModel catalogueViewModel)
{
if (catalogueViewModel.SelectedCategoryId == 0)
{
this.ModelState.AddModelError("SelectedCategoryId", "Please select a category.");
}
var vm = await this.catalogueService.GetCatalogueAsync(catalogueViewModel.CatalogueNodeVersionId);
vm.SelectedCategoryId = catalogueViewModel.SelectedCategoryId;
var vr = await this.catalogueService.AddCategoryToCatalogue(vm);
if (vr.Success)
{
var categories = await this.moodleApiService.GetAllMoodleCategoriesAsync();
vm.MoodleCategories = categories;
// Build hierarchical select list
var selectList = BuildList(categories, parentId: null, depth: 0);

foreach (var item in selectList)
{
item.Text = WebUtility.HtmlDecode(item.Text);
}

vm.MoodleCategorySelectList = new SelectList(selectList, "Value", "Text");
return this.View("MoodleCategory", vm);
}
else
{
this.ViewBag.ErrorMessage = $"Category Update failed.";
return this.View("MoodleCategory", vm);
}
}

/// <summary>
/// The RemoveCategoryFromCatalogue.
/// </summary>
/// <param name="categoryId">The categoryId/>.</param>
/// <param name="catalogueNodeVersionId">The CatalogueNodeVersionId.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
[HttpGet]
[Route("RemoveCategoryFromCatalogue/{categoryId}/{catalogueNodeVersionId}")]
public async Task<IActionResult> RemoveCategoryFromCatalogue(int categoryId, int catalogueNodeVersionId)
{
var vm = await this.catalogueService.GetCatalogueAsync(catalogueNodeVersionId);
vm.SelectedCategoryId = categoryId;
var vr = await this.catalogueService.RemoveCategoryFromCatalogue(vm);
if (vr.Success)
{
var categories = await this.moodleApiService.GetAllMoodleCategoriesAsync();
vm.MoodleCategories = categories;
vm.SelectedCategoryId = 0;
// Build hierarchical select list
var selectList = BuildList(categories, parentId: null, depth: 0);
foreach (var item in selectList)
{
item.Text = WebUtility.HtmlDecode(item.Text);
}
vm.MoodleCategorySelectList = new SelectList(selectList, "Value", "Text");
return this.View("MoodleCategory", vm);
}
else
{
this.ViewBag.ErrorMessage = $"Category update failed.";
return this.View("MoodleCategory", vm);
}
}
/// <summary>
/// The CreateCatalogue.
/// </summary>
Expand Down Expand Up @@ -978,5 +1089,34 @@ private void ValidateCatalogueOwnerVm(CatalogueOwnerViewModel vm)
this.ModelState.AddModelError("Notes", "The notes are required.");
}
}

private List<SelectListItem> BuildList(IEnumerable<MoodleCategory> allCategories, int? parentId, int depth)
{
var selectList = new List<SelectListItem>();

// Handle both null and 0 as top-level depending on Moodle data
var children = allCategories
.Where(c => c.Parent == parentId || (parentId == null && (c.Parent == 0 || c.Parent == 0)))
.OrderBy(c => c.Name)
.ToList();

foreach (var child in children)
{
// Indent with non-breaking spaces so browser keeps them
string indent = new string('\u00A0', depth * 3);

selectList.Add(new SelectListItem
{
Value = child.Id.ToString(),
Text = $"{indent}{child.Name}"
});

// Recursively add nested children
selectList.AddRange(BuildList(allCategories, child.Id, depth + 1));
}

return selectList;
}

}
}
14 changes: 14 additions & 0 deletions AdminUI/LearningHub.Nhs.AdminUI/Interfaces/ICatalogueService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,19 @@ public interface ICatalogueService
/// <param name="catalogueOwner">The catalogue owner<see cref="CatalogueOwnerViewModel"/>.</param>
/// <returns>The <see cref="Task"/>.</returns>
Task<ApiResponse> UpdateCatalogueOwnerAsync(CatalogueOwnerViewModel catalogueOwner);

/// <summary>
/// AddCategoryToCatalogue
/// </summary>
/// <param name="catalogue">The catalogue.</param>
/// <returns></returns>
Task<ApiResponse> AddCategoryToCatalogue(CatalogueViewModel catalogue);

/// <summary>
/// RemoveCategoryFromCatalogue
/// </summary>
/// <param name="catalogue">The catalogue.</param>
/// <returns></returns>
Task<ApiResponse> RemoveCategoryFromCatalogue(CatalogueViewModel catalogue);
}
}
26 changes: 26 additions & 0 deletions AdminUI/LearningHub.Nhs.AdminUI/Interfaces/IMoodleApiService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
namespace LearningHub.Nhs.AdminUI.Interfaces
{
using System.Collections.Generic;
using System.Threading.Tasks;
using LearningHub.Nhs.Models.Moodle;
using LearningHub.Nhs.Models.Moodle.API;

/// <summary>
/// IMoodleApiService.
/// </summary>
public interface IMoodleApiService
{
/// <summary>
/// GetMoodleUserIdByUsernameAsync.
/// </summary>
/// <param name="currentUserId">The current LH User Id.</param>
/// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
Task<int> GetMoodleUserIdByUsernameAsync(int currentUserId);

/// <summary>
/// GetEnrolledCoursesAsync.
/// </summary>
/// <returns> List of MoodleCategory.</returns>
Task<List<MoodleCategory>> GetAllMoodleCategoriesAsync();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
<PackageReference Include="HtmlSanitizer" Version="6.0.453" />
<PackageReference Include="IdentityModel" Version="4.6.0" />
<PackageReference Include="LearningHub.Nhs.Caching" Version="2.0.2" />
<PackageReference Include="LearningHub.Nhs.Models" Version="4.0.2" />
<PackageReference Include="LearningHub.Nhs.Models" Version="4.0.3" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.19.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.36" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.36" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public enum CatalogueNavPage
/// Defines the Catalogue Owner.
/// </summary>
CatalogueOwner,

/// <summary>
/// Defines the Category.
/// </summary>
Category
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur
services.AddTransient<IUserSessionHelper, UserSessionHelper>();
services.AddTransient<IInternalSystemService, InternalSystemService>();
services.AddScoped<IProviderService, ProviderService>();
services.AddScoped<IMoodleApiService, MoodleApiService>();

// web settings binding
var webSettings = new WebSettings();
Expand Down
26 changes: 26 additions & 0 deletions AdminUI/LearningHub.Nhs.AdminUI/Services/CatalogueService.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
namespace LearningHub.Nhs.AdminUI.Services
{
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using LearningHub.Nhs.AdminUI.Helpers;
using LearningHub.Nhs.AdminUI.Interfaces;
using LearningHub.Nhs.Models.Catalogue;
using LearningHub.Nhs.Models.Common;
using LearningHub.Nhs.Models.Enums;
using LearningHub.Nhs.Models.Paging;
using LearningHub.Nhs.Models.Provider;
using LearningHub.Nhs.Models.User;
using LearningHub.Nhs.Models.Validation;
using Newtonsoft.Json;

/// <summary>
Expand Down Expand Up @@ -132,5 +138,25 @@ public async Task<ApiResponse> UpdateCatalogueOwnerAsync(CatalogueOwnerViewModel
{
return await this.facade.PutAsync("Catalogue/UpdateCatalogueOwner", catalogueOwner);
}

/// <summary>
/// The AddUserGroupsToCatalogue.
/// </summary>
/// <param name="catalogue">The CatalogueViewModel.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
public async Task<ApiResponse> AddCategoryToCatalogue(CatalogueViewModel catalogue)
{
return await this.facade.PostAsync<ApiResponse, CatalogueViewModel>("Catalogue/AddCategoryToCatalogue", catalogue);
}

/// <summary>
/// The RemoveCategoryFromCatalogue.
/// </summary>
/// <param name="catalogue">The CatalogueViewModel.</param>
/// <returns>The <see cref="Task{IActionResult}"/>.</returns>
public async Task<ApiResponse> RemoveCategoryFromCatalogue(CatalogueViewModel catalogue)
{
return await this.facade.PostAsync<ApiResponse, CatalogueViewModel>("Catalogue/RemoveCategoryFromCatalogue", catalogue);
}
}
}
Loading
Loading