diff --git a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs index 9f0ab58aec..df086021b6 100644 --- a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs @@ -139,7 +139,7 @@ int EnrolOnActivitySelfAssessment(int selfAssessmentId, int candidateId, int sup public IEnumerable GetDelegateAssessmentStatisticsAtCentre(string searchString, int centreId, string categoryName, string isActive, int? categoryId); bool IsSelfEnrollmentAllowed(int customisationId); - Customisation? GetCourse(int customisationId); + Customisation? GetCourse(int? customisationId); } public class CourseDataService : ICourseDataService @@ -2024,7 +2024,7 @@ public bool IsSelfEnrollmentAllowed(int customisationId) return selfRegister > 0; } - public Customisation? GetCourse(int customisationId) + public Customisation? GetCourse(int? customisationId) { return connection.Query( @"SELECT CustomisationID diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs index 20f9f52ab2..1da83a6d65 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/CandidateAssessmentsDataService.cs @@ -8,7 +8,7 @@ public partial class SelfAssessmentDataService { - public IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId) + public IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId, int? adminCategoryId) { return connection.Query( @"SELECT SelfAssessment.Id, @@ -67,7 +67,7 @@ Competencies AS C RIGHT OUTER JOIN CandidateAssessmentSupervisorVerifications AS casv ON casv.CandidateAssessmentSupervisorID = cas.ID LEFT OUTER JOIN AdminAccounts AS aaEnrolledBy ON aaEnrolledBy.ID = CA.EnrolledByAdminID LEFT OUTER JOIN Users AS uEnrolledBy ON uEnrolledBy.ID = aaEnrolledBy.UserID - WHERE (CA.DelegateUserID = @delegateUserId) AND (CA.RemovedDate IS NULL) AND (CA.CompletedDate IS NULL) + WHERE (CA.DelegateUserID = @delegateUserId) AND (CA.RemovedDate IS NULL) AND (CA.CompletedDate IS NULL) AND (ISNULL(@adminCategoryId, 0) = 0 OR sa.CategoryID = @adminCategoryId) GROUP BY CA.SelfAssessmentID, SA.Name, SA.Description, SA.IncludesSignposting, SA.SupervisorResultsReview, SA.ReviewerCommentsLabel, SA.IncludeRequirementsFilters, @@ -83,7 +83,7 @@ CandidateAssessments AS CA LEFT OUTER JOIN (casv.Verified IS NOT NULL) GROUP BY SelfAssessmentID,casv.SignedOff )Signoff ON SelfAssessment.Id =Signoff.SelfAssessmentID", - new { delegateUserId, centreId } + new { delegateUserId, centreId, adminCategoryId } ); } diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs index e10185bf18..346fa62112 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs @@ -72,7 +72,7 @@ int competencyId // CandidateAssessmentsDataService - IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId); + IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId, int? adminCategoryId); CurrentSelfAssessment? GetSelfAssessmentForCandidateById(int delegateUserId, int selfAssessmentId); diff --git a/DigitalLearningSolutions.Data/Helpers/FilteringHelper.cs b/DigitalLearningSolutions.Data/Helpers/FilteringHelper.cs index 4ea7ae9ebe..a806df3f5d 100644 --- a/DigitalLearningSolutions.Data/Helpers/FilteringHelper.cs +++ b/DigitalLearningSolutions.Data/Helpers/FilteringHelper.cs @@ -66,8 +66,7 @@ public static string BuildFilterValueString(string group, string propertyName, s ? defaultFilterValue : AddNewFilterToFilterString(existingFilterString, newFilterToAdd); } - - public static string? GetCategoryAndTopicFilterString( + public static string? GetCategoryAndTopicFilterString( string? categoryFilterString, string? topicFilterString ) @@ -168,7 +167,59 @@ public static string GetFilterValueForRegistrationPrompt(int promptNumber, strin : answer; return BuildFilterValueString(group, group.Split('(')[0], propertyValue); } + public static string? GetValidFilters(string existingFilterString, string newFilterToAdd, IEnumerable availableFilters, HttpRequest request, string cookieName) + { + var cookieValue = request.Cookies[cookieName]; + if (string.IsNullOrEmpty(cookieValue) || cookieValue == EmptyFiltersCookieValue) + { + return existingFilterString; + } + var existingFilters = cookieValue.Split(FilterSeparator); + var validFilterValues = availableFilters + .SelectMany(filter => filter.FilterOptions) + .Select(option => option.FilterValue) + .ToHashSet(); + + var filteredResults = existingFilters + .Where(entry => IsFilterInvalid(entry, validFilterValues)) + .ToList(); + var newCookieValue = string.Join(FilterSeparator, filteredResults); + if (string.IsNullOrEmpty(newCookieValue)) return null; + newCookieValue = AddNewFilterToFilterString(newCookieValue, newFilterToAdd); + return RemoveDuplicateFilters( newFilterToAdd, newCookieValue); + } + private static bool IsFilterInvalid(string filterEntry, HashSet validFilterValues) + { + if (validFilterValues.Contains(filterEntry)) return true; + return false; + } + public static string RemoveDuplicateFilters(string newFilterToAdd, string? existingFilterString) + { + if (string.IsNullOrEmpty(existingFilterString)) + { + return existingFilterString ?? string.Empty; + } + var selectedFilters = existingFilterString.Split(FilteringHelper.FilterSeparator).ToList(); + if (!string.IsNullOrEmpty(newFilterToAdd)) + { + var filterHeader = newFilterToAdd.Split(FilteringHelper.Separator)[0]; + var dupfilters = selectedFilters.Where(x => x.Contains(filterHeader)); + if (dupfilters.Count() > 1) + { + foreach (var filter in selectedFilters) + { + if (filter.Contains(filterHeader)) + { + selectedFilters.Remove(filter); + existingFilterString = string.Join(FilteringHelper.FilterSeparator, selectedFilters); + break; + } + } + } + } + return existingFilterString; + } private static IEnumerable GetFilterOptionsForPromptWithOptions(Prompt prompt) { var group = GetFilterGroupForPrompt(prompt); diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/CurrentTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/CurrentTests.cs index 46c6f0685e..245c727128 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/CurrentTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/LearningPortal/CurrentTests.cs @@ -44,7 +44,7 @@ bool apiIsAccessible var bannerText = "bannerText"; A.CallTo(() => courseService.GetCurrentCourses(CandidateId)).Returns(currentCourses); - A.CallTo(() => selfAssessmentService.GetSelfAssessmentsForCandidate(DelegateUserId, A._)).Returns(selfAssessments); + A.CallTo(() => selfAssessmentService.GetSelfAssessmentsForCandidate(DelegateUserId, A._, A._)).Returns(selfAssessments); A.CallTo(() => actionPlanService.GetIncompleteActionPlanResources(DelegateUserId)) .Returns((actionPlanResources, apiIsAccessible)); A.CallTo(() => centresService.GetBannerText(CentreId)).Returns(bannerText); @@ -426,7 +426,7 @@ public void MarkActionPlanResourceAsComplete_does_not_call_service_with_invalid_ private void GivenCurrentActivitiesAreEmptyLists() { A.CallTo(() => courseService.GetCurrentCourses(A._)).Returns(new List()); - A.CallTo(() => selfAssessmentService.GetSelfAssessmentsForCandidate(A._, A._)) + A.CallTo(() => selfAssessmentService.GetSelfAssessmentsForCandidate(A._, A._, A._)) .Returns(new List()); A.CallTo(() => actionPlanService.GetIncompleteActionPlanResources(A._)) .Returns((new List(), false)); diff --git a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/Current.cs b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/Current.cs index d77ae9f556..ed30c74566 100644 --- a/DigitalLearningSolutions.Web/Controllers/LearningPortalController/Current.cs +++ b/DigitalLearningSolutions.Web/Controllers/LearningPortalController/Current.cs @@ -44,7 +44,7 @@ public async Task Current( var centreId = User.GetCentreIdKnownNotNull(); var selfAssessments = - selfAssessmentService.GetSelfAssessmentsForCandidate(delegateUserId, centreId); + selfAssessmentService.GetSelfAssessmentsForCandidate(delegateUserId, centreId, 0); var (learningResources, apiIsAccessible) = await GetIncompleteActionPlanResourcesIfSignpostingEnabled(delegateUserId); @@ -81,7 +81,7 @@ public async Task AllCurrentItems() var centreId = User.GetCentreIdKnownNotNull(); var selfAssessment = - selfAssessmentService.GetSelfAssessmentsForCandidate(delegateUserId, centreId); + selfAssessmentService.GetSelfAssessmentsForCandidate(delegateUserId, centreId, 0); var (learningResources, _) = await GetIncompleteActionPlanResourcesIfSignpostingEnabled(delegateUserId); var model = new AllCurrentItemsPageViewModel(currentCourses, selfAssessment, learningResources); diff --git a/DigitalLearningSolutions.Web/Controllers/Register/ClaimAccountController.cs b/DigitalLearningSolutions.Web/Controllers/Register/ClaimAccountController.cs index 2f25c02be0..bda98a8ad8 100644 --- a/DigitalLearningSolutions.Web/Controllers/Register/ClaimAccountController.cs +++ b/DigitalLearningSolutions.Web/Controllers/Register/ClaimAccountController.cs @@ -297,22 +297,18 @@ public IActionResult AdminAccountAlreadyExists(string email, string centreName) return RedirectToAction("AccessDenied", "LearningSolutions"); } - var adminAccounts = userService.GetUserById(loggedInUserId)!.AdminAccounts; + var userEntity = userService.GetUserById(loggedInUserId); - if (adminAccounts.Any()) + if (userEntity.DelegateAccounts!.Any(account => account.CentreId == model.CentreId)) { - return RedirectToAction( - "AdminAccountAlreadyExists", + return RedirectToAction("AccountAlreadyExists", new { email = model.Email, centreName = model.CentreName } ); } - var delegateAccounts = userService.GetUserById(loggedInUserId)!.DelegateAccounts; - - if (delegateAccounts.Any(account => account.CentreId == model.CentreId)) + if (userEntity.AdminAccounts!.Any(account => account.CentreId == model.CentreId)) { - return RedirectToAction( - "AccountAlreadyExists", + return RedirectToAction("AdminAccountAlreadyExists", new { email = model.Email, centreName = model.CentreName } ); } diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs index bfa04cd271..eea76c00d7 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs @@ -95,8 +95,7 @@ public IActionResult Index( sortBy ??= DefaultSortByOptions.Name.PropertyName; sortDirection ??= GenericSortingHelper.Ascending; - - existingFilterString = FilteringHelper.GetFilterString( + existingFilterString = FilteringHelper.GetFilterString( existingFilterString, newFilterToAdd, clearFilters, @@ -142,25 +141,7 @@ public IActionResult Index( if (!string.IsNullOrEmpty(existingFilterString)) { var selectedFilters = existingFilterString.Split(FilteringHelper.FilterSeparator).ToList(); - - if (!string.IsNullOrEmpty(newFilterToAdd)) - { - var filterHeader = newFilterToAdd.Split(FilteringHelper.Separator)[0]; - var dupfilters = selectedFilters.Where(x => x.Contains(filterHeader)); - if (dupfilters.Count() > 1) - { - foreach (var filter in selectedFilters) - { - if (filter.Contains(filterHeader)) - { - selectedFilters.Remove(filter); - existingFilterString = string.Join(FilteringHelper.FilterSeparator, selectedFilters); - break; - } - } - } - } - + existingFilterString = FilteringHelper.RemoveDuplicateFilters(newFilterToAdd, existingFilterString); if (selectedFilters.Count > 0) { foreach (var filter in selectedFilters) @@ -276,7 +257,10 @@ public IActionResult Index( var activityName = isCourseDelegate ? courseService.GetCourseNameAndApplication((int)customisationId).CourseName : selfAssessmentService.GetSelfAssessmentNameById((int)selfAssessmentId); - + if (!string.IsNullOrEmpty(existingFilterString)) + { + existingFilterString = FilteringHelper.GetValidFilters( existingFilterString, newFilterToAdd, availableFilters, Request, filterCookieName); + } if (isCourseDelegate) { var result = paginateService.Paginate( @@ -591,6 +575,7 @@ DelegateAccessRoute accessedVia return RedirectToAction("Index", "ActivityDelegates", routeData, returnPageQuery.Value.ItemIdToReturnTo); } } + } } diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ViewDelegateController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ViewDelegateController.cs index 32589d77a9..e0c157e3f2 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ViewDelegateController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ViewDelegateController.cs @@ -81,9 +81,10 @@ public IActionResult Index(int delegateId, string? callType) course.LastUpdated = DateHelper.GetLocalDateTime(course.LastUpdated); course.Completed = course.Completed?.TimeOfDay == TimeSpan.Zero ? course.Completed : DateHelper.GetLocalDateTime(course.Completed); } + var selfAssessments = - selfAssessmentService.GetSelfAssessmentsForCandidate(delegateEntity.UserAccount.Id, centreId); + selfAssessmentService.GetSelfAssessmentsForCandidate(delegateEntity.UserAccount.Id, centreId, categoryIdFilter); foreach (var selfassessment in selfAssessments) { diff --git a/DigitalLearningSolutions.Web/Services/CourseService.cs b/DigitalLearningSolutions.Web/Services/CourseService.cs index 9c255baf2e..530d34c22c 100644 --- a/DigitalLearningSolutions.Web/Services/CourseService.cs +++ b/DigitalLearningSolutions.Web/Services/CourseService.cs @@ -134,7 +134,7 @@ int diagCompletionThreshold int GetNumberOfActiveCoursesAtCentreFilteredByCategory(int centreId, int? categoryId); public IEnumerable GetApplicationsAvailableToCentre(int centreId); bool IsSelfEnrollmentAllowed(int customisationId); - Customisation? GetCourse(int customisationId); + Customisation? GetCourse(int? customisationId); } public class CourseService : ICourseService @@ -632,7 +632,7 @@ public bool IsSelfEnrollmentAllowed(int customisationId) return courseDataService.IsSelfEnrollmentAllowed(customisationId); } - public Customisation? GetCourse(int customisationId) + public Customisation? GetCourse(int? customisationId) { return courseDataService.GetCourse(customisationId); } diff --git a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs index 61e92bb72b..102af0b0b1 100644 --- a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs @@ -15,7 +15,7 @@ public interface ISelfAssessmentService //Self Assessments string? GetSelfAssessmentNameById(int selfAssessmentId); // Candidate Assessments - IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId); + IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId, int? adminCategoryId); CurrentSelfAssessment? GetSelfAssessmentForCandidateById(int delegateUserId, int selfAssessmentId); @@ -404,9 +404,9 @@ public IEnumerable GetCandidateAssessmentOptionalCompetencies(int se return selfAssessmentDataService.GetCandidateAssessmentOptionalCompetencies(selfAssessmentId, delegateUserId); } - public IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId) + public IEnumerable GetSelfAssessmentsForCandidate(int delegateUserId, int centreId, int? adminCategoryId) { - return selfAssessmentDataService.GetSelfAssessmentsForCandidate(delegateUserId, centreId); + return selfAssessmentDataService.GetSelfAssessmentsForCandidate(delegateUserId, centreId, adminCategoryId); } public IEnumerable GetMostRecentResults(int selfAssessmentId, int delegateId)