From 3ff0fc75cbba114e7fd314402e0c0827e4c3cd1e Mon Sep 17 00:00:00 2001 From: Binon Date: Thu, 31 Jul 2025 09:34:16 +0100 Subject: [PATCH 1/4] Removed moodle models in WebUI --- .../Shared/Tenant/LearningHub/_Layout.cshtml | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml index 6b679b67..1214ec0f 100644 --- a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml @@ -170,15 +170,17 @@ @functions { public async Task DisplayOffline() { - if (ViewContext.RouteData.Values["controller"].ToString() != "Offline" && User.Identity.IsAuthenticated) - { - var internalSystem = await this.internalSystemService.GetByIdAsync((int)InternalSystemType.LearningHub); - - return internalSystem.IsOffline; - } - else - { - return false; - } + return false; + + // if (ViewContext.RouteData.Values["controller"].ToString() != "Offline" && User.Identity.IsAuthenticated) + // { + // var internalSystem = await this.internalSystemService.GetByIdAsync((int)InternalSystemType.LearningHub); + + // return internalSystem.IsOffline; + // } + // else + // { + // return false; + // } } } \ No newline at end of file From c60e16546c2bf98b4f08a95fb2c696e922acd3b2 Mon Sep 17 00:00:00 2001 From: Binon Date: Thu, 31 Jul 2025 09:34:54 +0100 Subject: [PATCH 2/4] Removed the Moodle models in WebUI --- .../Helpers/ResourceTypeEnumMoodle.cs | 82 --------- .../Helpers/UtilityHelper.cs | 66 +------ .../LearningHub.Nhs.WebUI.csproj | 2 +- .../MoodleCompletionResponseViewModel.cs | 28 --- .../Models/MoodleCourseCompletionViewModel.cs | 103 ----------- .../Models/MoodleCourseResponseViewModel.cs | 165 ------------------ .../Models/MoodleOverviewFileViewModel.cs | 38 ---- .../Models/MoodleUserResponseViewModel.cs | 121 ------------- .../Services/MoodleApiService.cs | 2 +- .../Services/SearchService.cs | 6 +- .../Views/Search/_ResourceSearchResult.cshtml | 2 +- .../LearningHub.Nhs.OpenApi.Services.csproj | 2 +- 12 files changed, 9 insertions(+), 608 deletions(-) delete mode 100644 LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs delete mode 100644 LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs delete mode 100644 LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs delete mode 100644 LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs delete mode 100644 LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs delete mode 100644 LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs diff --git a/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs b/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs deleted file mode 100644 index e0601d15..00000000 --- a/LearningHub.Nhs.WebUI/Helpers/ResourceTypeEnumMoodle.cs +++ /dev/null @@ -1,82 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Helpers; - -/// -/// Represents the types of resources available in Moodle. -/// -public enum ResourceTypeEnumMoodle -{ - /// - /// The undefined resource type. - /// - Undefined, - - /// - /// The article resource type. - /// - Article, - - /// - /// The audio resource type. - /// - Audio, - - /// - /// The embedded resource type. - /// - Embedded, - - /// - /// The equipment resource type. - /// - Equipment, - - /// - /// The image resource type. - /// - Image, - - /// - /// The SCORM resource type. - /// - Scorm, - - /// - /// The video resource type. - /// - Video, - - /// - /// The web link resource type. - /// - WebLink, - - /// - /// The generic file resource type. - /// - GenericFile, - - /// - /// The clinical case resource type. - /// - Case, - - /// - /// The assessment resource type. - /// - Assessment, - - /// - /// The HTML resource type. - /// - Html, - - /// - /// The Moodle resource type. - /// - Moodle, - - /// - /// The Moodle course resource type. - /// - Course, -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs index c07ab98e..e1732d5a 100644 --- a/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs +++ b/LearningHub.Nhs.WebUI/Helpers/UtilityHelper.cs @@ -19,24 +19,6 @@ public static class UtilityHelper /// Findwise resource type dictionary. /// public static readonly Dictionary FindwiseResourceTypeDict = new Dictionary() - { - { "video", ResourceTypeEnum.Video }, - { "article", ResourceTypeEnum.Article }, - { "case", ResourceTypeEnum.Case }, - { "weblink", ResourceTypeEnum.WebLink }, - { "audio", ResourceTypeEnum.Audio }, - { "scorm", ResourceTypeEnum.Scorm }, - { "assessment", ResourceTypeEnum.Assessment }, - { "genericfile", ResourceTypeEnum.GenericFile }, - { "image", ResourceTypeEnum.Image }, - { "html", ResourceTypeEnum.Html }, - }; - - /// TODO: Remove this method after adding to Moodle resource types to models project. - /// - /// Findwise Moodle resource type dictionary. - /// - public static readonly Dictionary FindwiseResourceMoodleTypeDict = new Dictionary() { { "video", ResourceTypeEnum.Video }, { "article", ResourceTypeEnum.Article }, @@ -166,52 +148,6 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType } } - /// TODO: Remove this method after adding to Moodle resource types to models project. - /// - /// Returns a prettified resource type name, suitable for display in the UI. Includes video/audio duration string. - /// - /// The resource type. - /// The media duration in milliseconds. - /// The resource type name, and duration if applicable. - public static string GetPrettifiedResourceTypeNameMoodle(ResourceTypeEnum resourceType, int? durationInMilliseconds = 0) - { - switch (resourceType) - { - case ResourceTypeEnum.Assessment: - return "Assessment"; - case ResourceTypeEnum.Article: - return "Article"; - case ResourceTypeEnum.Audio: - string durationText = GetDurationText(durationInMilliseconds ?? 0); - durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; - return "Audio" + durationText; - case ResourceTypeEnum.Equipment: - return "Equipment"; - case ResourceTypeEnum.Image: - return "Image"; - case ResourceTypeEnum.Scorm: - return "elearning"; - case ResourceTypeEnum.Video: - durationText = GetDurationText(durationInMilliseconds ?? 0); - durationText = string.IsNullOrEmpty(durationText) ? string.Empty : " - " + durationText; - return "Video" + durationText; - case ResourceTypeEnum.WebLink: - return "Web link"; - case ResourceTypeEnum.GenericFile: - return "File"; - case ResourceTypeEnum.Embedded: - return "Embedded"; - case ResourceTypeEnum.Case: - return "Case"; - case ResourceTypeEnum.Html: - return "HTML"; - case ResourceTypeEnum.Moodle: - return "Course"; - default: - return "File"; - } - } - /// /// Returns a prettified resource type name, suitable for display in the UI. Excludes video/audio duration string. /// @@ -245,6 +181,8 @@ public static string GetPrettifiedResourceTypeName(ResourceTypeEnum resourceType return "Case"; case ResourceTypeEnum.Html: return "HTML"; + case ResourceTypeEnum.Moodle: + return "Course"; default: return "File"; } diff --git a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj index dc2cf661..b69ead58 100644 --- a/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj +++ b/LearningHub.Nhs.WebUI/LearningHub.Nhs.WebUI.csproj @@ -113,7 +113,7 @@ - + diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs deleted file mode 100644 index 1692a32e..00000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleCompletionResponseViewModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - /// - /// MoodleCompletionResponseViewModel. - /// - public class MoodleCompletionResponseViewModel - { - /// - /// Gets or sets the completion status. - /// - public string Exception { get; set; } - - /// - /// Gets or sets error code. - /// - public string Errorcode { get; set; } - - /// - /// Gets or sets Error message. - /// - public string Message { get; set; } - - /// - /// Gets or sets Debug info. - /// - public string Debuginfo { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs deleted file mode 100644 index 06eb5cb8..00000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleCourseCompletionViewModel.cs +++ /dev/null @@ -1,103 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - using System.Collections.Generic; - - /// - /// MoodleCourseCompletionViewModel. - /// - public class MoodleCourseCompletionViewModel - { - /// - /// Gets or sets the completion status. - /// - public CompletStatus CompletionStatus { get; set; } - - /// - /// Gets or sets the list of warnings. - /// - public List Warnings { get; set; } - - /// - /// CompletionStatus. - /// - public class CompletStatus - { - /// - /// Gets or sets a value indicating whether the course is completed. - /// - public bool Completed { get; set; } - - /// - /// Gets or sets the aggregation method. - /// - public int Aggregation { get; set; } - - /// - /// Gets or sets the list of completions. - /// - public List Completions { get; set; } - - /// - /// Completion. - /// - public class Completion - { - /// - /// Gets or sets the type of completion. - /// - public int Type { get; set; } - - /// - /// Gets or sets the title of the completion requirement. - /// - public string Title { get; set; } - - /// - /// Gets or sets the status of the completion. - /// - public string Status { get; set; } - - /// - /// Gets or sets a value indicating whether the requirement is complete. - /// - public bool Complete { get; set; } - - /// - /// Gets or sets the timestamp when completion was achieved. - /// - public long? TimeCompleted { get; set; } - - /// - /// Gets or sets the completion details. - /// - public CompletionDetails Details { get; set; } - - /// - /// CompletionDetails. - /// - public class CompletionDetails - { - /// - /// Gets or sets the type of completion requirement. - /// - public string Type { get; set; } - - /// - /// Gets or sets the criteria for completion. - /// - public string Criteria { get; set; } - - /// - /// Gets or sets the requirement for completion. - /// - public string Requirement { get; set; } - - /// - /// Gets or sets the status of the requirement. - /// - public string Status { get; set; } - } - } - } - } -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs deleted file mode 100644 index b214cf07..00000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleCourseResponseViewModel.cs +++ /dev/null @@ -1,165 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - using System.Collections.Generic; - - /// - /// MoodleCourseResponseViewModel. - /// - public class MoodleCourseResponseViewModel - { - /// - /// Gets or sets the ID. - /// - public int? Id { get; set; } - - /// - /// Gets or sets the short name. - /// - public string ShortName { get; set; } - - /// - /// Gets or sets the full name. - /// - public string FullName { get; set; } - - /// - /// Gets or sets the display name. - /// - public string DisplayName { get; set; } - - /// - /// Gets or sets the enrolled user count. - /// - public int? EnrolledUserCount { get; set; } - - /// - /// Gets or sets the ID number. - /// - public string IdNumber { get; set; } - - /// - /// Gets or sets the visibility status. - /// - public int? Visible { get; set; } - - /// - /// Gets or sets the summary. - /// - public string Summary { get; set; } - - /// - /// Gets or sets the summary format. - /// - public int? SummaryFormat { get; set; } - - /// - /// Gets or sets the format. - /// - public string Format { get; set; } - - /// - /// Gets or sets the course image URL. - /// - public string CourseImage { get; set; } - - /// - /// Gets or sets a value indicating whether grades are shown. - /// - public bool? ShowGrades { get; set; } - - /// - /// Gets or sets the language. - /// - public string Lang { get; set; } - - /// - /// Gets or sets a value indicating whether completion is enabled. - /// - public bool? EnableCompletion { get; set; } - - /// - /// Gets or sets a value indicating whether completion has criteria. - /// - public bool? CompletionHasCriteria { get; set; } - - /// - /// Gets or sets a value indicating whether completion is user-tracked. - /// - public bool? CompletionUserTracked { get; set; } - - /// - /// Gets or sets the category ID. - /// - public int? Category { get; set; } - - /// - /// Gets the progress percentage formatted as a string. - /// - public string ProgressPercentage => $"{System.Math.Round(this.Progress ?? 0)}%"; - - /// - /// Gets or sets the progress. - /// - public double? Progress { get; set; } - - /// - /// Gets or sets the completion status. - /// - public bool? Completed { get; set; } - - /// - /// Gets or sets the start date (Unix timestamp). - /// - public long? StartDate { get; set; } - - /// - /// Gets or sets the end date. - /// - public int? EndDate { get; set; } - - /// - /// Gets or sets the marker. - /// - public int? Marker { get; set; } - - /// - /// Gets or sets the last access timestamp. - /// - public int? LastAccess { get; set; } - - /// - /// Gets or sets a value indicating whether the course is a favorite. - /// - public bool? IsFavourite { get; set; } - - /// - /// Gets or sets a value indicating whether the course is hidden. - /// - public bool? Hidden { get; set; } - - /// - /// Gets or sets the list of overview files. - /// - public List OverviewFiles { get; set; } - - /// - /// Gets or sets a value indicating whether activity dates are shown. - /// - public bool? ShowActivityDates { get; set; } - - /// - /// Gets or sets a value indicating whether completion conditions are shown. - /// - public bool? ShowCompletionConditions { get; set; } - - /// - /// Gets or sets the last modified timestamp (Unix timestamp). - /// - public long? TimeModified { get; set; } - - /// - /// Gets or sets the moodle course completion view model. - /// - public MoodleCourseCompletionViewModel CourseCompletionViewModel { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs deleted file mode 100644 index 3dd335c4..00000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleOverviewFileViewModel.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - /// - /// MoodleOverviewFileViewModel. - /// - public class MoodleOverviewFileViewModel - { - /// - /// Gets or sets the file name. - /// - public string? FileName { get; set; } - - /// - /// Gets or sets the file path. - /// - public string? FilePath { get; set; } - - /// - /// Gets or sets the file size in bytes. - /// - public int FileSize { get; set; } - - /// - /// Gets or sets the file URL. - /// - public string? FileUrl { get; set; } - - /// - /// Gets or sets the time the file was modified (Unix timestamp). - /// - public long TimeModified { get; set; } - - /// - /// Gets or sets the MIME type of the file. - /// - public string? MimeType { get; set; } - } -} diff --git a/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs b/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs deleted file mode 100644 index 7940dc72..00000000 --- a/LearningHub.Nhs.WebUI/Models/MoodleUserResponseViewModel.cs +++ /dev/null @@ -1,121 +0,0 @@ -namespace LearningHub.Nhs.WebUI.Models -{ - using System.Collections.Generic; - - /// - /// MoodleUserResponseViewModel. - /// - public class MoodleUserResponseViewModel - { - /// - /// Gets or sets the list of users. - /// - public List Users { get; set; } - - /// - /// Gets or sets the warnings. - /// - public List Warnings { get; set; } - - /// - /// MoodleUser. - /// - public class MoodleUser - { - /// - /// Gets or sets the user ID. - /// - public int Id { get; set; } - - /// - /// Gets or sets the username. - /// - public string Username { get; set; } - - /// - /// Gets or sets the first name. - /// - public string FirstName { get; set; } - - /// - /// Gets or sets the last name. - /// - public string LastName { get; set; } - - /// - /// Gets or sets the full name. - /// - public string FullName { get; set; } - - /// - /// Gets or sets the email. - /// - public string Email { get; set; } - - /// - /// Gets or sets the department. - /// - public string Department { get; set; } - - /// - /// Gets or sets the first access timestamp. - /// - public long FirstAccess { get; set; } - - /// - /// Gets or sets the last access timestamp. - /// - public long LastAccess { get; set; } - - /// - /// Gets or sets the authentication method. - /// - public string Auth { get; set; } - - /// - /// Gets or sets a value indicating whether the user is suspended. - /// - public bool Suspended { get; set; } - - /// - /// Gets or sets a value indicating whether the user is confirmed. - /// - public bool Confirmed { get; set; } - - /// - /// Gets or sets the language. - /// - public string Lang { get; set; } - - /// - /// Gets or sets the theme. - /// - public string Theme { get; set; } - - /// - /// Gets or sets the timezone. - /// - public string Timezone { get; set; } - - /// - /// Gets or sets the mail format. - /// - public int MailFormat { get; set; } - - /// - /// Gets or sets the forum tracking preference. - /// - public int TrackForums { get; set; } - - /// - /// Gets or sets the small profile image URL. - /// - public string ProfileImageUrlSmall { get; set; } - - /// - /// Gets or sets the profile image URL. - /// - public string ProfileImageUrl { get; set; } - } - } -} diff --git a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs index fb69d3ee..2c4d3acc 100644 --- a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs +++ b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs @@ -139,7 +139,7 @@ public async Task GetCourseCompletionAsync(int user { var result = response.Content.ReadAsStringAsync().Result; - var canViewReport = JsonConvert.DeserializeObject(result); + var canViewReport = JsonConvert.DeserializeObject(result); if (string.IsNullOrEmpty(canViewReport.Exception)) { diff --git a/LearningHub.Nhs.WebUI/Services/SearchService.cs b/LearningHub.Nhs.WebUI/Services/SearchService.cs index 578a5861..333848a3 100644 --- a/LearningHub.Nhs.WebUI/Services/SearchService.cs +++ b/LearningHub.Nhs.WebUI/Services/SearchService.cs @@ -164,10 +164,10 @@ public async Task PerformSearch(IPrincipal user, SearchRe { var filter = filters.Where(x => x.DisplayName == filteritem).FirstOrDefault(); - if (filter != null && UtilityHelper.FindwiseResourceMoodleTypeDict.ContainsKey(filter.DisplayName)) + if (filter != null && UtilityHelper.FindwiseResourceTypeDict.ContainsKey(filter.DisplayName)) { - var resourceTypeEnum = UtilityHelper.FindwiseResourceMoodleTypeDict[filter.DisplayName]; - var searchfilter = new SearchFilterModel() { DisplayName = UtilityHelper.GetPrettifiedResourceTypeNameMoodle(resourceTypeEnum), Count = filter.Count, Value = filteritem, Selected = searchRequest.Filters?.Contains(filter.DisplayName) ?? false }; + var resourceTypeEnum = UtilityHelper.FindwiseResourceTypeDict[filter.DisplayName]; + var searchfilter = new SearchFilterModel() { DisplayName = UtilityHelper.GetPrettifiedResourceTypeName(resourceTypeEnum), Count = filter.Count, Value = filteritem, Selected = searchRequest.Filters?.Contains(filter.DisplayName) ?? false }; searchfilters.Add(searchfilter); } } diff --git a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml index 81156cd9..1db24b70 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml @@ -93,7 +93,7 @@
Type: - @UtilityHelper.GetPrettifiedResourceTypeNameMoodle(UtilityHelper.ToEnum(item.ResourceType), 0) + @UtilityHelper.GetPrettifiedResourceTypeName(UtilityHelper.ToEnum(item.ResourceType), 0)
@if (item.ResourceType != "moodle") 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 9002a023..bf7b23c2 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/LearningHub.Nhs.OpenApi.Services.csproj @@ -30,7 +30,7 @@ - + From 5eedd65bc2c8899c9778fcff5cd9d71b0aa580a5 Mon Sep 17 00:00:00 2001 From: Binon Date: Thu, 31 Jul 2025 17:13:17 +0100 Subject: [PATCH 3/4] Moved entrolled courses function to openAPI --- .../Interfaces/IMoodleApiService.cs | 9 -- .../Interfaces/IMoodleHttpClient.cs | 23 ---- .../Services/DashboardService.cs | 14 +-- .../Services/MoodleApiService.cs | 93 +++----------- .../Services/MoodleHttpClient.cs | 87 ------------- .../Startup/ServiceMappings.cs | 10 -- .../Shared/Tenant/LearningHub/_Layout.cshtml | 22 ++-- .../Configuration/MoodleConfig.cs | 16 ++- ...gHub.Nhs.OpenApi.Services.Interface.csproj | 2 +- .../Services/IMoodleApiService.cs | 21 +++- .../HttpClients/MoodleHttpClient.cs | 18 +-- .../Services/MoodleApiService.cs | 116 ++++++++++++++++-- .../Controllers/MoodleController.cs | 44 ++++++- .../LearningHub.Nhs.OpenApi/appsettings.json | 6 +- 14 files changed, 225 insertions(+), 256 deletions(-) delete mode 100644 LearningHub.Nhs.WebUI/Interfaces/IMoodleHttpClient.cs delete mode 100644 LearningHub.Nhs.WebUI/Services/MoodleHttpClient.cs diff --git a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs index 60dc18cb..03ff433a 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs @@ -24,14 +24,5 @@ public interface IMoodleApiService /// pageNumber. /// List of MoodleCourseResponseModel. Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber); - - /// - /// GetEnrolledCoursesAsync. - /// - /// Moodle user id. - /// Moodle course id. - /// pageNumber. - /// List of MoodleCourseResponseModel. - Task GetCourseCompletionAsync(int userId, int courseId, int pageNumber); } } diff --git a/LearningHub.Nhs.WebUI/Interfaces/IMoodleHttpClient.cs b/LearningHub.Nhs.WebUI/Interfaces/IMoodleHttpClient.cs deleted file mode 100644 index 3348a20a..00000000 --- a/LearningHub.Nhs.WebUI/Interfaces/IMoodleHttpClient.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace LearningHub.Nhs.Services.Interface -{ - using System.Net.Http; - using System.Threading.Tasks; - - /// - /// The Moodle Http Client interface. - /// - public interface IMoodleHttpClient - { - /// - /// The get cient async. - /// - /// The . - Task GetClient(); - - /// - /// GetDefaultParameters. - /// - /// defaultParameters. - string GetDefaultParameters(); - } -} \ No newline at end of file diff --git a/LearningHub.Nhs.WebUI/Services/DashboardService.cs b/LearningHub.Nhs.WebUI/Services/DashboardService.cs index d0470839..f0dfce65 100644 --- a/LearningHub.Nhs.WebUI/Services/DashboardService.cs +++ b/LearningHub.Nhs.WebUI/Services/DashboardService.cs @@ -2,15 +2,11 @@ { using System; using System.Collections.Generic; - using System.Net.Http; - using System.Runtime.InteropServices.WindowsRuntime; using System.Text; using System.Threading.Tasks; using LearningHub.Nhs.Models.Dashboard; using LearningHub.Nhs.Models.Entities.Analytics; - using LearningHub.Nhs.Models.Entities.Reporting; using LearningHub.Nhs.Models.Moodle.API; - using LearningHub.Nhs.Services.Interface; using LearningHub.Nhs.WebUI.Interfaces; using LearningHub.Nhs.WebUI.Models; using Microsoft.Extensions.Logging; @@ -21,19 +17,15 @@ /// public class DashboardService : BaseService, IDashboardService { - private readonly IMoodleHttpClient moodleHttpClient; - /// /// Initializes a new instance of the class. /// /// learningHubHttpClient. /// The Open Api Http Client. /// logger. - /// MoodleHttpClient. - public DashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IMoodleHttpClient moodleHttpClient) + public DashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) : base(learningHubHttpClient, openApiHttpClient, logger) { - this.moodleHttpClient = moodleHttpClient; } /// @@ -132,7 +124,7 @@ public async Task GetResourcesAsync(string d public async Task> GetEnrolledCoursesFromMoodleAsync(int currentUserId, int pageNumber) { List viewmodel = new List { }; - MoodleApiService moodleApiService = new MoodleApiService(this.moodleHttpClient, this.OpenApiHttpClient); + MoodleApiService moodleApiService = new MoodleApiService(this.OpenApiHttpClient); viewmodel = await moodleApiService.GetEnrolledCoursesAsync(currentUserId, pageNumber); return viewmodel; } @@ -144,7 +136,7 @@ public async Task> GetEnrolledCoursesFromMoodleA /// A representing the result of the asynchronous operation. public async Task GetMoodleUserIdAsync(int currentUserId) { - MoodleApiService moodleApiService = new MoodleApiService(this.moodleHttpClient, this.OpenApiHttpClient); + MoodleApiService moodleApiService = new MoodleApiService(this.OpenApiHttpClient); var moodleUserId = await moodleApiService.GetMoodleUserIdByUsernameAsync(currentUserId); return moodleUserId; } diff --git a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs index 2c4d3acc..4a2fb5cd 100644 --- a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs +++ b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs @@ -2,33 +2,24 @@ { using System; using System.Collections.Generic; - using System.Net.Http; - using System.Text; - using System.Text.Json; using System.Threading.Tasks; using LearningHub.Nhs.Models.Moodle.API; - using LearningHub.Nhs.Services.Interface; using LearningHub.Nhs.WebUI.Interfaces; - using LearningHub.Nhs.WebUI.Models; using Newtonsoft.Json; - using MoodleCourseCompletionModel = Nhs.Models.Moodle.API.MoodleCourseCompletionModel; /// /// MoodleApiService. /// public class MoodleApiService : IMoodleApiService { - private readonly IMoodleHttpClient moodleHttpClient; private readonly IOpenApiHttpClient openApiHttpClient; /// /// Initializes a new instance of the class. /// - /// moodleHttpClient. /// The Open Api Http Client. - public MoodleApiService(IMoodleHttpClient moodleHttpClient, IOpenApiHttpClient openApiHttpClient) + public MoodleApiService(IOpenApiHttpClient openApiHttpClient) { - this.moodleHttpClient = moodleHttpClient; this.openApiHttpClient = openApiHttpClient; } @@ -70,89 +61,37 @@ public async Task GetMoodleUserIdByUsernameAsync(int currentUserId) /// /// GetEnrolledCoursesAsync. /// - /// Moodle user id. + /// Moodle user id. /// The page Number. /// A representing the result of the asynchronous operation. - public async Task> GetEnrolledCoursesAsync(int userId, int pageNumber) + public async Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber) { - List viewmodel = new List { }; - MoodleApiService moodleApiService = new MoodleApiService(this.moodleHttpClient, this.openApiHttpClient); + List viewmodel = new List(); - var client = await this.moodleHttpClient.GetClient(); - string additionalParameters = $"userid={userId}"; - string defaultParameters = this.moodleHttpClient.GetDefaultParameters(); - string url = $"&wsfunction=core_enrol_get_users_courses&{additionalParameters}"; - - HttpResponseMessage response = await client.GetAsync("?" + defaultParameters + url); - - if (response.IsSuccessStatusCode) + try { - var result = response.Content.ReadAsStringAsync().Result; + var client = await this.openApiHttpClient.GetClientAsync(); - using var document = JsonDocument.Parse(result); - var root = document.RootElement; + var request = $"Moodle/GetEnrolledCourses/{currentUserId}"; + var response = await client.GetAsync(request).ConfigureAwait(false); - // Check if it's a JSON object and contains "exception" - if (!(root.ValueKind == JsonValueKind.Object && root.TryGetProperty("exception", out _))) + if (response.IsSuccessStatusCode) { + var result = response.Content.ReadAsStringAsync().Result; viewmodel = JsonConvert.DeserializeObject>(result); - - foreach (var course in viewmodel) - { - course.CourseCompletionViewModel = await moodleApiService.GetCourseCompletionAsync(userId, course.Id.Value, pageNumber); - } } - else + else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden) { - // Contains error, handle it as needed. + throw new Exception("AccessDenied"); } - } - else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || - response.StatusCode == System.Net.HttpStatusCode.Forbidden) - { - throw new Exception("AccessDenied"); - } - - return viewmodel; - } - /// - /// GetEnrolledCoursesAsync. - /// - /// Moodle user id. - /// Moodle course id. - /// pageNumber. - /// List of MoodleCourseResponseModel. - public async Task GetCourseCompletionAsync(int userId, int courseId, int pageNumber) - { - MoodleCourseCompletionModel viewmodel = new MoodleCourseCompletionModel { }; - MoodleApiService moodleApiService = new MoodleApiService(this.moodleHttpClient, this.openApiHttpClient); - - var client = await this.moodleHttpClient.GetClient(); - string additionalParameters = $"userid={userId}&courseid={courseId}"; - string defaultParameters = this.moodleHttpClient.GetDefaultParameters(); - string url = $"&wsfunction=core_completion_get_course_completion_status&{additionalParameters}"; - - HttpResponseMessage response = await client.GetAsync("?" + defaultParameters + url); - - if (response.IsSuccessStatusCode) - { - var result = response.Content.ReadAsStringAsync().Result; - - var canViewReport = JsonConvert.DeserializeObject(result); - - if (string.IsNullOrEmpty(canViewReport.Exception)) - { - viewmodel = JsonConvert.DeserializeObject(result); - } + return viewmodel; } - else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || - response.StatusCode == System.Net.HttpStatusCode.Forbidden) + catch (Exception ex) { - throw new Exception("AccessDenied"); + // this.Logger.LogError(string.Format("Error occurred in GetSearchResultAsync: {0}", ex.Message)); + return viewmodel; } - - return viewmodel; } } } diff --git a/LearningHub.Nhs.WebUI/Services/MoodleHttpClient.cs b/LearningHub.Nhs.WebUI/Services/MoodleHttpClient.cs deleted file mode 100644 index 79f44027..00000000 --- a/LearningHub.Nhs.WebUI/Services/MoodleHttpClient.cs +++ /dev/null @@ -1,87 +0,0 @@ -namespace LearningHub.Nhs.Services -{ - using System; - using System.Net.Http; - using System.Net.Http.Headers; - using System.Threading.Tasks; - using LearningHub.Nhs.Services.Interface; - using Microsoft.Extensions.Configuration; - - /// - /// The Moodle Http Client. - /// - public class MoodleHttpClient : IMoodleHttpClient, IDisposable - { - private readonly HttpClient httpClient = new (); - private bool initialised = false; - private string moodleAPIBaseUrl; - private string moodleAPIMoodleWSRestFormat; - private string moodleAPIWSToken; - - /// - /// Initializes a new instance of the class. - /// - /// httpClient. - /// config. - public MoodleHttpClient(HttpClient httpClient, IConfiguration config) - { - this.httpClient = httpClient; - this.moodleAPIBaseUrl = config["MoodleAPIConfig:BaseUrl"] + "webservice/rest/server.php"; - this.moodleAPIMoodleWSRestFormat = config["MoodleAPIConfig:MoodleWSRestFormat"]; - this.moodleAPIWSToken = config["MoodleAPIConfig:WSToken"]; - } - - /// - /// The Get Client method. - /// - /// The . - public async Task GetClient() - { - this.Initialise(this.moodleAPIBaseUrl); - return this.httpClient; - } - - /// - /// GetDefaultParameters. - /// - /// defaultParameters. - public string GetDefaultParameters() - { - string defaultParameters = $"wstoken={this.moodleAPIWSToken}" - + $"&moodlewsrestformat={this.moodleAPIMoodleWSRestFormat}"; - - return defaultParameters; - } - - /// - 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.initialised = true; - } - } - } -} diff --git a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs index 0a0c04c4..eca24695 100644 --- a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs +++ b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs @@ -3,8 +3,6 @@ using System.Net.Http; using GDS.MultiPageFormData; using LearningHub.Nhs.Models.OpenAthens; - using LearningHub.Nhs.Services; - using LearningHub.Nhs.Services.Interface; using LearningHub.Nhs.WebUI.Filters; using LearningHub.Nhs.WebUI.Helpers; using LearningHub.Nhs.WebUI.Interfaces; @@ -62,13 +60,6 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, }); - services.AddHttpClient() - .ConfigurePrimaryHttpMessageHandler( - () => new HttpClientHandler - { - ServerCertificateCustomValidationCallback = - HttpClientHandler.DangerousAcceptAnyServerCertificateValidator, - }); } else { @@ -76,7 +67,6 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon services.AddHttpClient(); services.AddHttpClient(); services.AddHttpClient(); - services.AddHttpClient(); } // Config diff --git a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml index 1214ec0f..6b679b67 100644 --- a/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Shared/Tenant/LearningHub/_Layout.cshtml @@ -170,17 +170,15 @@ @functions { public async Task DisplayOffline() { - return false; - - // if (ViewContext.RouteData.Values["controller"].ToString() != "Offline" && User.Identity.IsAuthenticated) - // { - // var internalSystem = await this.internalSystemService.GetByIdAsync((int)InternalSystemType.LearningHub); - - // return internalSystem.IsOffline; - // } - // else - // { - // return false; - // } + if (ViewContext.RouteData.Values["controller"].ToString() != "Offline" && User.Identity.IsAuthenticated) + { + var internalSystem = await this.internalSystemService.GetByIdAsync((int)InternalSystemType.LearningHub); + + return internalSystem.IsOffline; + } + else + { + return false; + } } } \ No newline at end of file diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleConfig.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleConfig.cs index de178b6a..20e9b190 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleConfig.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Models/Configuration/MoodleConfig.cs @@ -14,16 +14,26 @@ public class MoodleConfig /// /// Gets or sets the base url for the Moodle service. /// - public string APIBaseUrl { get; set; } = null!; + public string ApiBaseUrl { get; set; } = null!; /// /// Gets or sets the Web service Rest Format. /// - public string APIWSRestFormat { get; set; } = null!; + public string ApiWsRestFormat { get; set; } = null!; /// /// Gets or sets the token. /// - public string APIWSToken { get; set; } = null!; + public string ApiWsToken { get; set; } = null!; + + /// + /// Gets or sets the token. + /// + public string ApiPath { get; set; } = "webservice/rest/server.php"; + + /// + /// Gets or sets the token. + /// + public string CoursePath { get; set; } = "course/view.php"; } } 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 aa019e18..6fe3b2df 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/IMoodleApiService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleApiService.cs index e366a437..ee573d43 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleApiService.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services.Interface/Services/IMoodleApiService.cs @@ -1,7 +1,5 @@ -using System; +using LearningHub.Nhs.Models.Moodle.API; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Threading.Tasks; namespace LearningHub.Nhs.OpenApi.Services.Interface.Services @@ -17,5 +15,22 @@ public interface IMoodleApiService /// The current LH User Id. /// A representing the result of the asynchronous operation. Task GetMoodleUserIdByUsernameAsync(int currentUserId); + + /// + /// GetEnrolledCoursesAsync. + /// + /// Moodle user id. + /// pageNumber. + /// List of MoodleCourseResponseModel. + Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber); + + /// + /// GetEnrolledCoursesAsync. + /// + /// Moodle user id. + /// Moodle course id. + /// pageNumber. + /// List of MoodleCourseResponseModel. + Task GetCourseCompletionAsync(int userId, int courseId, int pageNumber); } } diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleHttpClient.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleHttpClient.cs index 73af9397..2c9fc410 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleHttpClient.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/HttpClients/MoodleHttpClient.cs @@ -20,9 +20,9 @@ public class MoodleHttpClient : IMoodleHttpClient, IDisposable private readonly HttpClient httpClient = new(); private bool initialised = false; - private string moodleAPIBaseUrl; - private string moodleAPIMoodleWSRestFormat; - private string moodleAPIWSToken; + private string moodleApiUrl; + private string moodleApiMoodleWsRestFormat; + private string moodleApiWsToken; /// /// Initializes a new instance of the class. @@ -34,9 +34,9 @@ public MoodleHttpClient(HttpClient httpClient, IOptions moodleConf this.moodleConfig = moodleConfig.Value; this.httpClient = httpClient; - this.moodleAPIBaseUrl = this.moodleConfig.APIBaseUrl + "webservice/rest/server.php"; - this.moodleAPIMoodleWSRestFormat = this.moodleConfig.APIWSRestFormat; - this.moodleAPIWSToken = this.moodleConfig.APIWSToken; + this.moodleApiUrl = this.moodleConfig.ApiBaseUrl + this.moodleConfig.ApiPath; + this.moodleApiMoodleWsRestFormat = this.moodleConfig.ApiWsRestFormat; + this.moodleApiWsToken = this.moodleConfig.ApiWsToken; } /// @@ -45,7 +45,7 @@ public MoodleHttpClient(HttpClient httpClient, IOptions moodleConf /// The . public async Task GetClient() { - this.Initialise(this.moodleAPIBaseUrl); + this.Initialise(this.moodleApiUrl); return this.httpClient; } @@ -55,8 +55,8 @@ public async Task GetClient() /// defaultParameters. public string GetDefaultParameters() { - string defaultParameters = $"wstoken={this.moodleAPIWSToken}" - + $"&moodlewsrestformat={this.moodleAPIMoodleWSRestFormat}"; + string defaultParameters = $"wstoken={this.moodleApiWsToken}" + + $"&moodlewsrestformat={this.moodleApiMoodleWsRestFormat}"; return defaultParameters; } diff --git a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs index 90ffc428..08786db8 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi.Services/Services/MoodleApiService.cs @@ -11,6 +11,7 @@ using System.Net; using System.Net.Http; using System.Text; + using System.Text.Json; using System.Threading.Tasks; /// @@ -31,6 +32,7 @@ public MoodleApiService(IMoodleHttpClient moodleHttpClient, ILogger /// GetMoodleUserIdByUsernameAsync. /// @@ -51,16 +53,89 @@ public async Task GetMoodleUserIdByUsernameAsync(int currentUserId) } + /// + /// GetEnrolledCoursesAsync. + /// + /// Moodle user id. + /// The page Number. + /// A representing the result of the asynchronous operation. + public async Task> GetEnrolledCoursesAsync(int userId, int pageNumber) + { + var parameters = new Dictionary + { + { "userid", userId.ToString() } + }; + + // Fetch enrolled courses + var enrolledCourses = await GetCallMoodleApiAsync>( + "core_enrol_get_users_courses", + parameters + ); + + if (enrolledCourses == null || enrolledCourses.Count == 0) + return new List(); + + // Load course completion info in parallel + var completionTasks = enrolledCourses + .Where(c => c.Id.HasValue) + .Select(async course => + { + try + { + course.CourseCompletionViewModel = await GetCourseCompletionAsync(userId, course.Id.Value, pageNumber); + } + catch (Exception ex) + { + course.CourseCompletionViewModel = new MoodleCourseCompletionModel + { + CompletionStatus = null, + }; + } + + return course; + }); + + var enrichedCourses = await Task.WhenAll(completionTasks); + + return enrichedCourses.ToList(); + + } + + /// + /// GetEnrolledCoursesAsync. + /// + /// Moodle user id. + /// Moodle course id. + /// pageNumber. + /// List of MoodleCourseResponseModel. + public async Task GetCourseCompletionAsync(int userId, int courseId, int pageNumber) + { + var parameters = new Dictionary + { + { "userid", userId.ToString() }, + { "courseid", courseId.ToString() } + }; + + // Call Moodle API and parse response + var result = await GetCallMoodleApiAsync("core_completion_get_course_completion_status", parameters); + + // If Moodle did not return an exception, return parsed completion data + if (result.Warnings.Count == 0) + { + // Optionally map/convert if needed + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(result)); + } + + return new MoodleCourseCompletionModel(); // Return empty model or null as fallback + } + private async Task GetCallMoodleApiAsync(string wsFunction, Dictionary parameters) { var client = await this.moodleHttpClient.GetClient(); string defaultParameters = this.moodleHttpClient.GetDefaultParameters(); - // Build URL query - var queryBuilder = new StringBuilder(); - - queryBuilder.Append($"&wsfunction={wsFunction}"); - + // Build URL query string + var queryBuilder = new StringBuilder($"&wsfunction={wsFunction}"); foreach (var param in parameters) { queryBuilder.Append($"&{param.Key}={Uri.EscapeDataString(param.Value)}"); @@ -73,7 +148,33 @@ private async Task GetCallMoodleApiAsync(string wsFunction, Dictionary(result); + // Moodle may still return an error with 200 OK + try + { + using var document = JsonDocument.Parse(result); + var root = document.RootElement; + + if (root.ValueKind == JsonValueKind.Object && root.TryGetProperty("exception", out var exceptionProp)) + { + string? message = root.TryGetProperty("message", out var messageProp) + ? messageProp.GetString() + : "Unknown error"; + + this.logger.LogError($"Moodle returned an exception: {exceptionProp.GetString()}, Message: {message}"); + throw new Exception($"Moodle API Error: {exceptionProp.GetString()}, Message: {message}"); + } + } + catch (System.Text.Json.JsonException ex) + { + this.logger.LogError(ex, "Failed to parse Moodle API response as JSON."); + throw; + } + + var deserialized = JsonConvert.DeserializeObject(result); + + return deserialized == null + ? throw new Exception($"Failed to deserialize Moodle API response into type {typeof(T).Name}. Raw response: {result}") + : deserialized; } else if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden) { @@ -82,9 +183,10 @@ private async Task GetCallMoodleApiAsync(string wsFunction, Dictionary @@ -14,14 +16,33 @@ public class MoodleController : Controller { private readonly IMoodleApiService moodleService; + private readonly MoodleConfig moodleConfig; /// /// Initializes a new instance of the class. /// /// The moodle service. - public MoodleController(IMoodleApiService moodleService) + /// Moodel config. + public MoodleController(IMoodleApiService moodleService, IOptions moodleConfig) { this.moodleService = moodleService; + this.moodleConfig = moodleConfig.Value; + } + + /// + /// The GetSafeMoodleConfig. + /// + /// The . + [HttpGet] + [Route("GetSafeMoodleConfig")] + public IActionResult GetSafeMoodleConfig() + { + // Only expose safe config values + return Ok(new + { + apiBaseUrl = this.moodleConfig.ApiBaseUrl, + coursePath = this.moodleConfig.CoursePath, + }); } /// @@ -43,5 +64,26 @@ public async Task GetMoodleUserId(int? currentUserId) return this.Ok(0); } } + + /// + /// GetEnrolledCoursesAsync. + /// + /// Moodle user id. + /// The page Number. + /// A representing the result of the asynchronous operation. + [HttpGet] + [Route("GetEnrolledCourses/{currentUserId?}")] + public async Task GetEnrolledCoursesAsync(int? currentUserId, int pageNumber = 0) + { + if (currentUserId.HasValue) + { + var entrolledCourses = await this.moodleService.GetEnrolledCoursesAsync(currentUserId.Value, pageNumber); + return this.Ok(entrolledCourses); + } + else + { + return this.Ok(0); + } + } } } diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json index 61417224..181c8eaf 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json +++ b/OpenAPI/LearningHub.Nhs.OpenApi/appsettings.json @@ -121,8 +121,8 @@ "AuthTimeout": 20 }, "Moodle": { - "APIBaseUrl": "", - "APIWSRestFormat": "json", - "APIWSToken": "" + "ApiBaseUrl": "", + "ApiWsRestFormat": "json", + "ApiWsToken": "" } } From 58da86806d2adcc86569858aa3c4378fd896c7bd Mon Sep 17 00:00:00 2001 From: Binon Date: Fri, 1 Aug 2025 12:10:23 +0100 Subject: [PATCH 4/4] tidied up some code --- .../Configuration/MoodleApiConfig.cs | 33 +++++++++++++++++++ .../Interfaces/IMoodleApiService.cs | 7 ++++ .../ServiceCollectionExtension.cs | 3 ++ .../Services/DashboardService.cs | 12 ++++--- .../Services/MoodleApiService.cs | 19 ++++++++++- .../Startup/ServiceMappings.cs | 1 + .../Views/Home/_CourseEnrolled.cshtml | 8 ++--- .../Views/Search/_ResourceSearchResult.cshtml | 29 +++++++++++----- .../Controllers/MoodleController.cs | 21 +----------- 9 files changed, 92 insertions(+), 41 deletions(-) create mode 100644 LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs diff --git a/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs b/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs new file mode 100644 index 00000000..ec874477 --- /dev/null +++ b/LearningHub.Nhs.WebUI/Configuration/MoodleApiConfig.cs @@ -0,0 +1,33 @@ +namespace LearningHub.Nhs.WebUI.Configuration +{ + /// + /// The Moodle Settings. + /// + public class MoodleApiConfig + { + /// + /// Gets or sets the base url for the Moodle service. + /// + public string BaseUrl { get; set; } = null!; + + /// + /// Gets or sets the Web service Rest Format. + /// + public string MoodleWSRestFormat { get; set; } = null!; + + /// + /// Gets or sets the token. + /// + public string WSToken { get; set; } = null!; + + /// + /// Gets or sets the token. + /// + public string ApiPath { get; set; } = "webservice/rest/server.php"; + + /// + /// Gets or sets the token. + /// + public string CoursePath { get; set; } = "course/view.php"; + } +} diff --git a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs index 03ff433a..5796c348 100644 --- a/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs +++ b/LearningHub.Nhs.WebUI/Interfaces/IMoodleApiService.cs @@ -24,5 +24,12 @@ public interface IMoodleApiService /// pageNumber. /// List of MoodleCourseResponseModel. Task> GetEnrolledCoursesAsync(int currentUserId, int pageNumber); + + /// + /// GetCourseUrl. + /// + /// course Id. + /// return course URL. + string GetCourseUrl(int courseId); } } diff --git a/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs b/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs index 5ed5cc92..eb2c2fa2 100644 --- a/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs +++ b/LearningHub.Nhs.WebUI/ServiceCollectionExtension.cs @@ -78,6 +78,9 @@ public static void ConfigureServices(this IServiceCollection services, IConfigur JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + var moodleApiSettings = configuration.GetSection("MoodleAPIConfig"); + services.Configure(moodleApiSettings); + var settingsSection = configuration.GetSection("Settings"); services.Configure(settingsSection); diff --git a/LearningHub.Nhs.WebUI/Services/DashboardService.cs b/LearningHub.Nhs.WebUI/Services/DashboardService.cs index f0dfce65..bde127b8 100644 --- a/LearningHub.Nhs.WebUI/Services/DashboardService.cs +++ b/LearningHub.Nhs.WebUI/Services/DashboardService.cs @@ -17,15 +17,19 @@ /// public class DashboardService : BaseService, IDashboardService { + private readonly IMoodleApiService moodleApiService; + /// /// Initializes a new instance of the class. /// /// learningHubHttpClient. /// The Open Api Http Client. /// logger. - public DashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger) + /// MoodleApiService. + public DashboardService(ILearningHubHttpClient learningHubHttpClient, IOpenApiHttpClient openApiHttpClient, ILogger logger, IMoodleApiService moodleApiService) : base(learningHubHttpClient, openApiHttpClient, logger) { + this.moodleApiService = moodleApiService; } /// @@ -124,8 +128,7 @@ public async Task GetResourcesAsync(string d public async Task> GetEnrolledCoursesFromMoodleAsync(int currentUserId, int pageNumber) { List viewmodel = new List { }; - MoodleApiService moodleApiService = new MoodleApiService(this.OpenApiHttpClient); - viewmodel = await moodleApiService.GetEnrolledCoursesAsync(currentUserId, pageNumber); + viewmodel = await this.moodleApiService.GetEnrolledCoursesAsync(currentUserId, pageNumber); return viewmodel; } @@ -136,8 +139,7 @@ public async Task> GetEnrolledCoursesFromMoodleA /// A representing the result of the asynchronous operation. public async Task GetMoodleUserIdAsync(int currentUserId) { - MoodleApiService moodleApiService = new MoodleApiService(this.OpenApiHttpClient); - var moodleUserId = await moodleApiService.GetMoodleUserIdByUsernameAsync(currentUserId); + var moodleUserId = await this.moodleApiService.GetMoodleUserIdByUsernameAsync(currentUserId); return moodleUserId; } diff --git a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs index 4a2fb5cd..c80a764f 100644 --- a/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs +++ b/LearningHub.Nhs.WebUI/Services/MoodleApiService.cs @@ -4,7 +4,9 @@ using System.Collections.Generic; using System.Threading.Tasks; using LearningHub.Nhs.Models.Moodle.API; + using LearningHub.Nhs.WebUI.Configuration; using LearningHub.Nhs.WebUI.Interfaces; + using Microsoft.Extensions.Options; using Newtonsoft.Json; /// @@ -13,14 +15,17 @@ public class MoodleApiService : IMoodleApiService { private readonly IOpenApiHttpClient openApiHttpClient; + private readonly MoodleApiConfig configuration; /// /// Initializes a new instance of the class. /// /// The Open Api Http Client. - public MoodleApiService(IOpenApiHttpClient openApiHttpClient) + /// configuration. + public MoodleApiService(IOpenApiHttpClient openApiHttpClient, IOptions configuration) { this.openApiHttpClient = openApiHttpClient; + this.configuration = configuration.Value; } /// @@ -93,5 +98,17 @@ public async Task> GetEnrolledCoursesAsync(int c return viewmodel; } } + + /// + /// GetCourseUrl. + /// + /// course Id. + /// return course URL. + public string GetCourseUrl(int courseId) + { + var apiBaseUrl = this.configuration.BaseUrl; + string path = this.configuration.CoursePath; + return $"{apiBaseUrl}{path}?id={courseId}"; + } } } diff --git a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs index eca24695..9fd65bd6 100644 --- a/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs +++ b/LearningHub.Nhs.WebUI/Startup/ServiceMappings.cs @@ -98,6 +98,7 @@ public static void AddLearningHubMappings(this IServiceCollection services, ICon services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddScoped(); services.AddScoped(); diff --git a/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml b/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml index f62eea9f..a7351226 100644 --- a/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Home/_CourseEnrolled.cshtml @@ -3,7 +3,7 @@ @using LearningHub.Nhs.WebUI.Extensions @using LearningHub.Nhs.WebUI.Helpers @model MoodleCourseResponseModel -@inject Microsoft.Extensions.Configuration.IConfiguration Configuration; +@inject LearningHub.Nhs.WebUI.Interfaces.IMoodleApiService moodleApiService; @{ bool providerExists = false; @@ -11,11 +11,7 @@ string GetMoodleCourseUrl(int courseId) { - var apiBaseUrl = Configuration["MoodleAPIConfig:BaseUrl"]; - string path = $"course/view.php"; - string returnUrl = $@"{apiBaseUrl}{path}?id={courseId}"; - - return returnUrl; + return moodleApiService.GetCourseUrl(courseId); } }
diff --git a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml index 1db24b70..50c8df8f 100644 --- a/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml +++ b/LearningHub.Nhs.WebUI/Views/Search/_ResourceSearchResult.cshtml @@ -1,5 +1,5 @@ @model LearningHub.Nhs.WebUI.Models.Search.SearchResultViewModel -@inject Microsoft.Extensions.Configuration.IConfiguration Configuration; +@inject LearningHub.Nhs.WebUI.Interfaces.IMoodleApiService moodleApiService; @using System.Linq; @using System.Web; @@ -28,19 +28,30 @@ &query={searchSignalQueryEncoded}&title={payload?.DocumentFields?.Title}"; } - string GetMoodleCourseUrl(string courseId) + string GetMoodleCourseUrl(string courseIdWithPrefix) { - var prefix = "M"; - if (courseId.StartsWith(prefix)) + const string prefix = "M"; + + if (string.IsNullOrWhiteSpace(courseIdWithPrefix)) + { + return string.Empty; + } + + if (!courseIdWithPrefix.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { - courseId = courseId.Replace(prefix, ""); ; + return string.Empty; } - var apiBaseUrl = Configuration["MoodleAPIConfig:BaseUrl"]; - string path = $"course/view.php"; - string returnUrl = $@"{apiBaseUrl}{path}?id={courseId}"; + var courseIdPart = courseIdWithPrefix.Substring(prefix.Length); - return returnUrl; + if (int.TryParse(courseIdPart, out int courseId)) + { + return moodleApiService.GetCourseUrl(courseId); + } + else + { + return string.Empty; + } } bool showCatalogueFieldsInResources = ViewBag.ShowCatalogueFieldsInResources == null || ViewBag.ShowCatalogueFieldsInResources == true; diff --git a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleController.cs b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleController.cs index 64624505..f2639d00 100644 --- a/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleController.cs +++ b/OpenAPI/LearningHub.Nhs.OpenApi/Controllers/MoodleController.cs @@ -16,33 +16,14 @@ public class MoodleController : Controller { private readonly IMoodleApiService moodleService; - private readonly MoodleConfig moodleConfig; /// /// Initializes a new instance of the class. /// /// The moodle service. - /// Moodel config. - public MoodleController(IMoodleApiService moodleService, IOptions moodleConfig) + public MoodleController(IMoodleApiService moodleService) { this.moodleService = moodleService; - this.moodleConfig = moodleConfig.Value; - } - - /// - /// The GetSafeMoodleConfig. - /// - /// The . - [HttpGet] - [Route("GetSafeMoodleConfig")] - public IActionResult GetSafeMoodleConfig() - { - // Only expose safe config values - return Ok(new - { - apiBaseUrl = this.moodleConfig.ApiBaseUrl, - coursePath = this.moodleConfig.CoursePath, - }); } ///