diff --git a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs index b56a099c1e..4c3ffd3190 100644 --- a/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/CourseDataService.cs @@ -137,6 +137,8 @@ int EnrolOnActivitySelfAssessment(int selfAssessmentId, int candidateId, int sup public IEnumerable GetDelegateCourseStatisticsAtCentre(string searchString, int centreId, int? categoryId, bool allCentreCourses, bool? hideInLearnerPortal, string isActive, string categoryName, string courseTopic, string hasAdminFields); public IEnumerable GetDelegateAssessmentStatisticsAtCentre(string searchString, int centreId, string categoryName, string isActive); + + public IEnumerable GetDelegateAssessmentStatisticsAtCentreByCategoryId(string searchString, int centreId, string categoryName, string isActive, int? categoryId); bool IsSelfEnrollmentAllowed(int customisationId); Customisation? GetCourse(int customisationId); } @@ -1995,6 +1997,46 @@ AND sa.[Name] LIKE '%' + @searchString + '%' return delegateAssessmentStatistics; } + + public IEnumerable GetDelegateAssessmentStatisticsAtCentreByCategoryId(string searchString, int centreId, string categoryName, string isActive, int? categoryId) + { + string assessmentStatisticsSelectQuery = $@"SELECT + sa.Name AS Name, + cc.CategoryName AS Category, + CASE + WHEN sa.SupervisorSelfAssessmentReview = 0 AND sa.SupervisorResultsReview = 0 THEN 0 + ELSE 1 + END AS Supervised, + (SELECT COUNT(can.ID) + FROM dbo.CandidateAssessments AS can WITH (NOLOCK) + INNER JOIN Users AS u WITH (NOLOCK) ON u.ID = can.DelegateUserID + LEFT JOIN UserCentreDetails AS ucd WITH (NOLOCK) ON ucd.UserID = u.ID AND ucd.centreID = can.CentreID + WHERE can.CentreID = @centreId AND can.SelfAssessmentID = csa.SelfAssessmentID + AND can.RemovedDate IS NULL AND COALESCE(ucd.Email, u.PrimaryEmail) LIKE '%_@_%') AS DelegateCount, + (Select COUNT(*) FROM + (SELECT can.ID FROM dbo.CandidateAssessments AS can WITH (NOLOCK) + LEFT JOIN dbo.CandidateAssessmentSupervisors AS cas ON can.ID = cas.CandidateAssessmentID + LEFT JOIN dbo.CandidateAssessmentSupervisorVerifications AS casv ON cas.ID = casv.CandidateAssessmentSupervisorID + WHERE can.CentreID = @centreId AND can.SelfAssessmentID = CSA.SelfAssessmentID AND can.RemovedDate IS NULL + AND (can.SubmittedDate IS NOT NULL OR (casv.SignedOff = 1 AND casv.Verified IS NOT NULL)) GROUP BY can.ID) A + ) AS SubmittedSignedOffCount, + CC.Active AS Active, + sa.ID AS SelfAssessmentId + from CentreSelfAssessments AS csa + INNER join SelfAssessments AS sa ON csa.SelfAssessmentID = sa.ID + INNER JOIN CourseCategories AS cc ON sa.CategoryID = cc.CourseCategoryID + WHERE csa.CentreID= @centreId + AND sa.[Name] LIKE '%' + @searchString + '%' + AND ((@categoryName = 'Any') OR (cc.CategoryName = @categoryName)) + AND (ISNULL(@categoryId, 0) = 0 OR sa.CategoryID = @categoryId) + AND ((@isActive = 'Any') OR (@isActive = 'true' AND sa.ArchivedDate IS NULL) OR (@isActive = 'false' AND sa.ArchivedDate IS NOT NULL)) + "; + + IEnumerable delegateAssessmentStatistics = connection.Query(assessmentStatisticsSelectQuery, + new { searchString, centreId, categoryName, isActive, categoryId }, commandTimeout: 3000); + return delegateAssessmentStatistics; + } + public bool IsSelfEnrollmentAllowed(int customisationId) { int selfRegister = connection.QueryFirstOrDefault( diff --git a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs index dcd7923df3..8c130d535c 100644 --- a/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/SelfAssessmentDataService/SelfAssessmentDataService.cs @@ -10,6 +10,7 @@ using DigitalLearningSolutions.Data.Models.Frameworks; using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Models.SelfAssessments.Export; + using MailKit; using Microsoft.Extensions.Logging; public interface ISelfAssessmentDataService @@ -172,6 +173,7 @@ int GetSelfAssessmentActivityDelegatesExportCount(string searchString, string so bool IsUnsupervisedSelfAssessment(int selfAssessmentId); bool IsCentreSelfAssessment(int selfAssessmentId, int centreId); bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId); + int GetSelfAssessmentCategoryId(int selfAssessmentId); } public partial class SelfAssessmentDataService : ISelfAssessmentDataService @@ -760,5 +762,13 @@ INNER JOIN SelfAssessments AS SA new { selfAssessmentId, delegateUserId } ); } + + public int GetSelfAssessmentCategoryId(int selfAssessmentId) + { + return connection.ExecuteScalar( + @"SELECT CategoryID FROM SelfAssessments WHERE ID = @selfAssessmentId", + new { selfAssessmentId} + ); + } } } diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/CourseDelegatesControllerTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/CourseDelegatesControllerTests.cs index 02b664d8d3..390d457b9f 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/CourseDelegatesControllerTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/CourseDelegatesControllerTests.cs @@ -23,6 +23,7 @@ public class CourseDelegatesControllerTests { private const int UserCentreId = 3; + private const int SelfAssessmentId = 1; private ActivityDelegatesController controller = null!; private ICourseDelegatesDownloadFileService courseDelegatesDownloadFileService = null!; private ICourseDelegatesService courseDelegatesService = null!; @@ -122,8 +123,10 @@ public void CourseDelegates_Index_returns_Not_Found_when_service_returns_null() ), 0) ); + A.CallTo(() => selfAssessmentDelegatesService.GetSelfAssessmentCategoryId(1)).Returns(1); + // When - var result = controller.Index(2); + var result = controller.Index(2,1); // Then result.Should().BeNotFoundResult(); @@ -155,6 +158,7 @@ public void Index_should_default_to_Active_filter() { // Given const int customisationId = 2; + const int selfAssessmentId = 2; var searchString = string.Empty; var sortBy = "SearchableName"; var sortDirection = "Ascending"; @@ -207,7 +211,7 @@ public void Index_should_default_to_Active_filter() ); // When - var result = courseDelegatesController.Index(customisationId); + var result = courseDelegatesController.Index(customisationId, selfAssessmentId); // Then using (new AssertionScope()) diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs index b8f86fa872..6f1178955b 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/ActivityDelegatesController.cs @@ -132,6 +132,13 @@ public IActionResult Index( var centreId = User.GetCentreIdKnownNotNull(); var adminCategoryId = User.GetAdminCategoryId(); + var selfAssessmentCategoryId = selfAssessmentService.GetSelfAssessmentCategoryId((int)selfAssessmentId); + + if (adminCategoryId > 0 && adminCategoryId != selfAssessmentCategoryId) + { + return RedirectToAction("StatusCode", "LearningSolutions", new { code = 403 }); + } + bool? isDelegateActive, isProgressLocked, removed, hasCompleted, submitted, signedOff; isDelegateActive = isProgressLocked = removed = hasCompleted = submitted = signedOff = null; diff --git a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/DelegateCoursesController.cs b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/DelegateCoursesController.cs index 0cbcd2c2bf..4b8109b0a0 100644 --- a/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/DelegateCoursesController.cs +++ b/DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/DelegateCoursesController.cs @@ -162,7 +162,7 @@ public IActionResult Index( if (isCourse == "true") delegateActivities = courseService.GetDelegateCourses(searchString ?? string.Empty, centreId, categoryId, true, null, isActive, categoryName, courseTopic, hasAdminFields).ToList(); if (isSelfAssessment == "true" && courseTopic == "Any" && hasAdminFields == "Any") - delegateAssessments = courseService.GetDelegateAssessments(searchString, centreId, categoryName, isActive); + delegateAssessments = courseService.GetDelegateAssessmentsByCategoryId(searchString, centreId, categoryName, isActive, categoryId); delegateAssessments = UpdateCompletedCount(delegateAssessments); diff --git a/DigitalLearningSolutions.Web/Services/CourseService.cs b/DigitalLearningSolutions.Web/Services/CourseService.cs index 5a9bc2d86a..306ef46651 100644 --- a/DigitalLearningSolutions.Web/Services/CourseService.cs +++ b/DigitalLearningSolutions.Web/Services/CourseService.cs @@ -121,6 +121,7 @@ int diagCompletionThreshold public IEnumerable GetDelegateCourses(string searchString, int centreId, int? categoryId, bool allCentreCourses, bool? hideInLearnerPortal, string isActive, string categoryName, string courseTopic, string hasAdminFields); public IEnumerable GetDelegateAssessments(string searchString, int centreId, string categoryName, string isActive); + public IEnumerable GetDelegateAssessmentsByCategoryId(string searchString, int centreId, string categoryName, string isActive, int? categoryId); IEnumerable GetAvailableCourses(int delegateId, int? centreId, int categoryId); bool IsCourseCompleted(int candidateId, int customisationId); bool IsCourseCompleted(int candidateId, int customisationId, int progressID); @@ -568,6 +569,11 @@ public IEnumerable GetDelegateAssessments(string s return courseDataService.GetDelegateAssessmentStatisticsAtCentre(searchString, centreId, categoryName, isActive); } + public IEnumerable GetDelegateAssessmentsByCategoryId(string searchString, int centreId, string categoryName, string isActive, int? categoryId) + { + return courseDataService.GetDelegateAssessmentStatisticsAtCentreByCategoryId(searchString, centreId, categoryName, isActive, categoryId); + } + public IEnumerable GetAvailableCourses(int delegateId, int? centreId, int categoryId) { return courseDataService.GetAvailableCourses(delegateId, centreId, categoryId); diff --git a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs index ff7ef8d53a..c342cfdfce 100644 --- a/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs +++ b/DigitalLearningSolutions.Web/Services/SelfAssessmentService.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; using DigitalLearningSolutions.Data.DataServices.SelfAssessmentDataService; + using DigitalLearningSolutions.Data.ModelBinders; using DigitalLearningSolutions.Data.Models.Common.Users; using DigitalLearningSolutions.Data.Models.External.Filtered; using DigitalLearningSolutions.Data.Models.Frameworks; @@ -149,6 +150,7 @@ public int GetSelfAssessmentActivityDelegatesExportCount(string searchString, st IEnumerable GetCandidateAssessments(int delegateUserId, int selfAssessmentId); bool IsCentreSelfAssessment(int selfAssessmentId, int centreId); bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUserId); + public int GetSelfAssessmentCategoryId(int selfAssessmentId); } @@ -558,5 +560,10 @@ public bool HasMinimumOptionalCompetencies(int selfAssessmentId, int delegateUse { return selfAssessmentDataService.HasMinimumOptionalCompetencies(selfAssessmentId, delegateUserId); } + + public int GetSelfAssessmentCategoryId(int selfAssessmentId) + { + return selfAssessmentDataService.GetSelfAssessmentCategoryId(selfAssessmentId); + } } }