1- namespace LearningHub . Nhs . AdminUI . Controllers
1+ using LearningHub . Nhs . Models . Databricks ;
2+ using Microsoft . AspNetCore . Mvc . Rendering ;
3+ using System . Net ;
4+
5+ namespace LearningHub . Nhs . AdminUI . Controllers
26{
7+ using AngleSharp . Io ;
8+ using Azure ;
39 using LearningHub . Nhs . AdminUI . Configuration ;
410 using LearningHub . Nhs . AdminUI . Extensions ;
11+ using LearningHub . Nhs . AdminUI . Helpers ;
512 using LearningHub . Nhs . AdminUI . Interfaces ;
613 using LearningHub . Nhs . AdminUI . Models ;
714 using LearningHub . Nhs . Models . Catalogue ;
815 using LearningHub . Nhs . Models . Common ;
16+ using LearningHub . Nhs . Models . Databricks ;
917 using LearningHub . Nhs . Models . Moodle ;
1018 using LearningHub . Nhs . Models . Paging ;
1119 using LearningHub . Nhs . Models . Resource ;
@@ -70,6 +78,11 @@ public class CatalogueController : BaseController
7078 /// </summary>
7179 private readonly IMoodleApiService moodleApiService ;
7280
81+ /// <summary>
82+ /// Defines the moodleApiService.
83+ /// </summary>
84+ private readonly IMoodleBridgeApiService moodleBridgeApiService ;
85+
7386 /// <summary>
7487 /// Defines the _settings.
7588 /// </summary>
@@ -104,6 +117,7 @@ public class CatalogueController : BaseController
104117 /// <param name="fileService">The fileService<see cref="IFileService"/>.</param>
105118 /// <param name="providerService">The providerService<see cref="IProviderService"/>.</param>
106119 /// <param name="moodleApiService">The moodleApiService<see cref="IMoodleApiService"/>.</param>
120+ /// <param name="moodleBridgeApiService">The moodleApiService<see cref="moodleBridgeApiService"/>.</param>
107121 /// <param name="logger">The logger<see cref="ILogger{LogController}"/>.</param>
108122 /// <param name="options">The options<see cref="IOptions{WebSettings}"/>.</param>
109123 /// <param name="websettings">The websettings<see cref="IOptions{WebSettings}"/>.</param>
@@ -114,6 +128,7 @@ public CatalogueController(
114128 IFileService fileService ,
115129 IProviderService providerService ,
116130 IMoodleApiService moodleApiService ,
131+ IMoodleBridgeApiService moodleBridgeApiService ,
117132 ILogger < LogController > logger ,
118133 IOptions < WebSettings > options ,
119134 IOptions < WebSettings > websettings )
@@ -124,6 +139,7 @@ public CatalogueController(
124139 this . fileService = fileService ;
125140 this . providerService = providerService ;
126141 this . moodleApiService = moodleApiService ;
142+ this . moodleBridgeApiService = moodleBridgeApiService ;
127143 this . logger = logger ;
128144 this . websettings = websettings ;
129145 this . settings = options . Value ;
@@ -277,17 +293,9 @@ public async Task<IActionResult> MoodleCategory(int id)
277293 return this . RedirectToAction ( "Error" ) ;
278294 }
279295
280- var categories = await this . moodleApiService . GetAllMoodleCategoriesAsync ( ) ;
296+ var categoriesResult = await this . moodleBridgeApiService . GetAllMoodleCategoriesAsync ( ) ;
281297
282- vm . MoodleCategories = categories ;
283-
284- // Build hierarchical select list
285- var selectList = BuildList ( categories , parentId : null , depth : 0 ) ;
286- foreach ( var item in selectList )
287- {
288- item . Text = WebUtility . HtmlDecode ( item . Text ) ;
289- }
290- vm . MoodleCategorySelectList = new SelectList ( selectList , "Value" , "Text" ) ;
298+ vm . MoodleCategorySelectList = BuildMoodleCategorySelectList ( categoriesResult ) ;
291299 this . ViewData [ "CatalogueName" ] = vm . Name ;
292300 this . ViewData [ "id" ] = id ;
293301
@@ -727,7 +735,7 @@ public async Task<IActionResult> AddUserGroupsToCatalogue(int catalogueNodeId, i
727735 [ Route ( "AddCategoryToCatalogue" ) ]
728736 public async Task < IActionResult > AddCategoryToCatalogue ( CatalogueViewModel catalogueViewModel )
729737 {
730- if ( catalogueViewModel . SelectedCategoryId == 0 )
738+ if ( string . IsNullOrEmpty ( catalogueViewModel . SelectedCategoryId ) )
731739 {
732740 this . ModelState . AddModelError ( "SelectedCategoryId" , "Please select a category." ) ;
733741 }
@@ -736,17 +744,8 @@ public async Task<IActionResult> AddCategoryToCatalogue(CatalogueViewModel catal
736744 var vr = await this . catalogueService . AddCategoryToCatalogue ( vm ) ;
737745 if ( vr . Success )
738746 {
739- var categories = await this . moodleApiService . GetAllMoodleCategoriesAsync ( ) ;
740- vm . MoodleCategories = categories ;
741- // Build hierarchical select list
742- var selectList = BuildList ( categories , parentId : null , depth : 0 ) ;
743-
744- foreach ( var item in selectList )
745- {
746- item . Text = WebUtility . HtmlDecode ( item . Text ) ;
747- }
748-
749- vm . MoodleCategorySelectList = new SelectList ( selectList , "Value" , "Text" ) ;
747+ var categories = await this . moodleBridgeApiService . GetAllMoodleCategoriesAsync ( ) ;
748+ vm . MoodleCategorySelectList = BuildMoodleCategorySelectList ( categories ) ;
750749 return this . View ( "MoodleCategory" , vm ) ;
751750 }
752751 else
@@ -764,23 +763,16 @@ public async Task<IActionResult> AddCategoryToCatalogue(CatalogueViewModel catal
764763 /// <returns>The <see cref="Task{IActionResult}"/>.</returns>
765764 [ HttpGet ]
766765 [ Route ( "RemoveCategoryFromCatalogue/{categoryId}/{catalogueNodeVersionId}" ) ]
767- public async Task < IActionResult > RemoveCategoryFromCatalogue ( int categoryId , int catalogueNodeVersionId )
766+ public async Task < IActionResult > RemoveCategoryFromCatalogue ( string categoryId , int catalogueNodeVersionId )
768767 {
769768 var vm = await this . catalogueService . GetCatalogueAsync ( catalogueNodeVersionId ) ;
770769 vm . SelectedCategoryId = categoryId ;
771770 var vr = await this . catalogueService . RemoveCategoryFromCatalogue ( vm ) ;
772771 if ( vr . Success )
773772 {
774- var categories = await this . moodleApiService . GetAllMoodleCategoriesAsync ( ) ;
775- vm . MoodleCategories = categories ;
776- vm . SelectedCategoryId = 0 ;
777- // Build hierarchical select list
778- var selectList = BuildList ( categories , parentId : null , depth : 0 ) ;
779- foreach ( var item in selectList )
780- {
781- item . Text = WebUtility . HtmlDecode ( item . Text ) ;
782- }
783- vm . MoodleCategorySelectList = new SelectList ( selectList , "Value" , "Text" ) ;
773+ var categories = await this . moodleBridgeApiService . GetAllMoodleCategoriesAsync ( ) ;
774+ vm . MoodleCategorySelectList = BuildMoodleCategorySelectList ( categories ) ;
775+ vm . SelectedCategoryId = null ;
784776 return this . View ( "MoodleCategory" , vm ) ;
785777 }
786778 else
@@ -1090,33 +1082,91 @@ private void ValidateCatalogueOwnerVm(CatalogueOwnerViewModel vm)
10901082 }
10911083 }
10921084
1093- private List < SelectListItem > BuildList ( IEnumerable < MoodleCategory > allCategories , int ? parentId , int depth )
1085+ public static SelectList BuildMoodleCategorySelectList ( IEnumerable < CategoryResult > results )
10941086 {
10951087 var selectList = new List < SelectListItem > ( ) ;
10961088
1097- // Handle both null and 0 as top-level depending on Moodle data
1098- var children = allCategories
1099- . Where ( c => c . Parent == parentId || ( parentId == null && ( c . Parent == 0 || c . Parent == 0 ) ) )
1100- . OrderBy ( c => c . Name )
1101- . ToList ( ) ;
1102-
1103- foreach ( var child in children )
1089+ foreach ( var result in results )
11041090 {
1105- // Indent with non-breaking spaces so browser keeps them
1106- string indent = new string ( ' \u00A0 ' , depth * 3 ) ;
1091+ if ( string . IsNullOrWhiteSpace ( result . Instance ) )
1092+ continue ;
11071093
1094+ // Instance header
11081095 selectList . Add ( new SelectListItem
11091096 {
1110- Value = child . Id . ToString ( ) ,
1111- Text = $ "{ indent } { child . Name } "
1097+ Value = "" ,
1098+ Text = result . Instance ,
1099+ Disabled = true ,
1100+ Selected = false
11121101 } ) ;
11131102
1114- // Recursively add nested children
1115- selectList . AddRange ( BuildList ( allCategories , child . Id , depth + 1 ) ) ;
1103+ // Handle instance error
1104+ if ( result . Error != null )
1105+ {
1106+ selectList . Add ( new SelectListItem
1107+ {
1108+ Value = "" ,
1109+ Text = "\u00A0 \u00A0 [Category unavailable]" ,
1110+ Disabled = true ,
1111+ Selected = false
1112+ } ) ;
1113+
1114+ continue ;
1115+ }
1116+
1117+ var categories = result . Data ? . Categories ;
1118+ if ( categories == null || ! categories . Any ( ) )
1119+ continue ;
1120+
1121+ var tree = categories
1122+ . GroupBy ( c => c . Parent )
1123+ . ToDictionary ( g => g . Key , g => g . OrderBy ( x => x . Name ) . ToList ( ) ) ;
1124+
1125+ TreeBuilderHelper . BuildTree ( selectList , tree , 0 , 1 , result . Instance ) ;
1126+ }
1127+
1128+ // Decode HTML entities
1129+ foreach ( var item in selectList )
1130+ {
1131+ item . Text = WebUtility . HtmlDecode ( item . Text ) ;
11161132 }
11171133
1118- return selectList ;
1134+ return new SelectList ( selectList , "Value" , "Text" ) ;
11191135 }
11201136
1137+ /// </summary>
1138+ /// <param name="selectList"></param>
1139+ /// <param name="tree"></param>
1140+ /// <param name="parentId"></param>
1141+ /// <param name="depth"></param>
1142+ /// <param name="instance"></param>
1143+ /// <param name="group"></param>
1144+
1145+ // Recursive tree builder with indentation
1146+ private static void BuildTree (
1147+ List < SelectListItem > selectList ,
1148+ Dictionary < int , List < MoodleCategory > > tree ,
1149+ int parentId ,
1150+ int depth ,
1151+ string instance ,
1152+ SelectListGroup group )
1153+ {
1154+ if ( ! tree . ContainsKey ( parentId ) )
1155+ return ;
1156+
1157+ foreach ( var category in tree [ parentId ] )
1158+ {
1159+ string indent = new string ( '\u00A0 ' , depth * 2 ) ;
1160+
1161+ selectList . Add ( new SelectListItem
1162+ {
1163+ Value = $ "{ instance } :{ category . Id } ",
1164+ Text = $ "{ indent } { category . Name } ",
1165+ Group = group
1166+ } ) ;
1167+
1168+ BuildTree ( selectList , tree , category . Id , depth + 1 , instance , group ) ;
1169+ }
1170+ }
11211171 }
11221172}
0 commit comments