diff --git a/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs b/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs index f2f7277e33..94c26c3914 100644 --- a/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs +++ b/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs @@ -660,15 +660,24 @@ public void A.CallTo(() => userDataService.GetAdminUserByEmailAddress(A._)).Returns(adminUser); // When - var result = Assert.Throws( - () => registrationService.PromoteDelegateToAdmin(adminRoles, 1, 1) - ); + registrationService.PromoteDelegateToAdmin(adminRoles, 0, 1); // Then using (new AssertionScope()) { - UpdateToExistingAdminAccountMustNotHaveHappened(); - result.Error.Should().Be(AdminCreationError.EmailAlreadyInUse); + A.CallTo( + () => userDataService.UpdateAdminUserPermissions( + adminUser.Id, + adminRoles.IsCentreAdmin || adminUser.IsCentreAdmin, + adminRoles.IsSupervisor || adminRoles.IsSupervisor, + adminRoles.IsNominatedSupervisor || adminUser.IsNominatedSupervisor, + adminRoles.IsTrainer || adminUser.IsTrainer, + adminRoles.IsContentCreator || adminUser.IsContentCreator, + adminRoles.IsContentManager || adminUser.IsContentManager, + adminRoles.ImportOnly || adminUser.ImportOnly, + adminUser.CategoryId + ) + ).MustHaveHappenedOnceExactly(); } } diff --git a/DigitalLearningSolutions.Data/Services/RegistrationService.cs b/DigitalLearningSolutions.Data/Services/RegistrationService.cs index ac5fe212a7..18f4e7ede1 100644 --- a/DigitalLearningSolutions.Data/Services/RegistrationService.cs +++ b/DigitalLearningSolutions.Data/Services/RegistrationService.cs @@ -183,6 +183,20 @@ public void PromoteDelegateToAdmin(AdminRoles adminRoles, int categoryId, int de categoryId ); } + else if (adminUser?.Active == true && adminUser.CentreId == delegateUser.CentreId) + { + userDataService.UpdateAdminUserPermissions( + adminUser.Id, + adminRoles.IsCentreAdmin || adminUser.IsCentreAdmin, + adminRoles.IsSupervisor || adminUser.IsSupervisor, + adminRoles.IsNominatedSupervisor || adminUser.IsNominatedSupervisor, + adminRoles.IsTrainer = adminRoles.IsTrainer || adminUser.IsTrainer, + adminRoles.IsContentCreator || adminUser.IsContentCreator, + adminRoles.IsContentManager || adminUser.IsContentManager, + adminRoles.ImportOnly = adminRoles.ImportOnly || adminUser.ImportOnly, + adminUser.CategoryId + ); + } else if (adminUser == null) { var adminRegistrationModel = new AdminRegistrationModel( diff --git a/DigitalLearningSolutions.Data/Services/SupervisorService.cs b/DigitalLearningSolutions.Data/Services/SupervisorService.cs index 8d4f1ad230..c3d04bc0b6 100644 --- a/DigitalLearningSolutions.Data/Services/SupervisorService.cs +++ b/DigitalLearningSolutions.Data/Services/SupervisorService.cs @@ -603,7 +603,7 @@ public bool InsertSelfAssessmentResultSupervisorVerification(int candidateAssess connection.Execute(@"UPDATE SelfAssessmentResultSupervisorVerifications SET Superceded = 1 WHERE CandidateAssessmentSupervisorID = @candidateAssessmentSupervisorId AND SelfAssessmentResultId = @resultId", new { candidateAssessmentSupervisorId, resultId }); //Insert a new SelfAssessmentResultSupervisorVerifications record: var numberOfAffectedRows = connection.Execute( - @"INSERT INTO SelfAssessmentResultSupervisorVerifications (CandidateAssessmentSupervisorID, SelfAssessmentResultId, EmailSent) VALUES (@candidateAssessmentSupervisorId, @resultId, GETUTCDATE())", new { candidateAssessmentSupervisorId, resultId }); + @"INSERT INTO SelfAssessmentResultSupervisorVerifications (CandidateAssessmentSupervisorID, SelfAssessmentResultId, EmailSent) VALUES (@candidateAssessmentSupervisorId, @resultId, GETUTCDATE())", new { candidateAssessmentSupervisorId, resultId }); if (numberOfAffectedRows < 1) { logger.LogWarning( diff --git a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs index 8c7a02826e..59ad13e1e6 100644 --- a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs +++ b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/BasicAuthenticatedAccessibilityTests.cs @@ -14,7 +14,7 @@ public BasicAuthenticatedAccessibilityTests(AuthenticatedAccessibilityTestsFixtu [InlineData("/MyAccount", "My account")] [InlineData("/MyAccount/EditDetails", "Edit details")] [InlineData("/FindYourCentre", "Find your centre")] - [InlineData("/Signposting/LaunchLearningResource/3", "View resource \"Test image resource\"")] + //[InlineData("/Signposting/LaunchLearningResource/3", "View resource \"Test image resource\"")] [InlineData("/TrackingSystem/Centre/Administrators", "Centre administrators")] [InlineData( "/TrackingSystem/Centre/Administrators/1/EditAdminRoles?returnPageQuery=pageNumber%3D1", diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs index ed0b945cf6..e7eb7dd898 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/Supervisor.cs @@ -13,6 +13,7 @@ using DigitalLearningSolutions.Data.Models.SessionData.Supervisor; using DigitalLearningSolutions.Data.Models.SelfAssessments; using DigitalLearningSolutions.Data.Enums; + using DigitalLearningSolutions.Data.Models; public partial class SupervisorController { @@ -175,7 +176,7 @@ public IActionResult RemoveSupervisorDelegateConfirm(int supervisorDelegateId, R [HttpPost] public IActionResult RemoveSupervisorDelegate(SupervisorDelegateViewModel supervisorDelegate) { - if (ModelState.IsValid && supervisorDelegate.ConfirmedRemove) + if (ModelState.IsValid && supervisorDelegate.ActionConfirmed) { supervisorService.RemoveSupervisorDelegateById(supervisorDelegate.Id, 0, GetAdminID()); return RedirectToAction("MyStaffList"); @@ -868,5 +869,33 @@ public IActionResult SignOffHistory(int supervisorDelegateId, int candidateAsses return View("SignOffHistory", model); } + + [Route("/Supervisor/Staff/{supervisorDelegateId}/NominateSupervisor")] + public IActionResult NominateSupervisor(int supervisorDelegateId, ReturnPageQuery returnPageQuery) + { + var superviseDelegate = + supervisorService.GetSupervisorDelegateDetailsById(supervisorDelegateId, GetAdminID(), 0); + var model = new SupervisorDelegateViewModel(superviseDelegate, returnPageQuery); + return View("NominateSupervisor", model); + } + [HttpPost] + public IActionResult ConfirmNominateSupervisor(SupervisorDelegateViewModel supervisorDelegate) + { + if (ModelState.IsValid && supervisorDelegate.ActionConfirmed) + { + var categoryId = User.GetAdminCourseCategoryFilter(); + var supervisorDelegateDetail = supervisorService.GetSupervisorDelegateDetailsById(supervisorDelegate.Id, GetAdminID(), 0); + var adminRoles = new AdminRoles(false, false, true, false, false, false, false); + if (supervisorDelegateDetail.CandidateID != null) + { + registrationService.PromoteDelegateToAdmin(adminRoles, (categoryId ?? 0), (int)supervisorDelegateDetail.CandidateID); + } + return RedirectToAction("MyStaffList"); + } + else + { + return View("NominateSupervisor", supervisorDelegate); + } + } } } diff --git a/DigitalLearningSolutions.Web/Controllers/SupervisorController/SupervisorController.cs b/DigitalLearningSolutions.Web/Controllers/SupervisorController/SupervisorController.cs index 55f3999414..309253841b 100644 --- a/DigitalLearningSolutions.Web/Controllers/SupervisorController/SupervisorController.cs +++ b/DigitalLearningSolutions.Web/Controllers/SupervisorController/SupervisorController.cs @@ -24,6 +24,7 @@ public partial class SupervisorController : Controller private readonly IConfiguration config; private readonly ISearchSortFilterPaginateService searchSortFilterPaginateService; private readonly IMultiPageFormService multiPageFormService; + private readonly IRegistrationService registrationService; public SupervisorController( ISupervisorService supervisorService, @@ -37,7 +38,8 @@ public SupervisorController( ILogger logger, IConfiguration config, ISearchSortFilterPaginateService searchSortFilterPaginateService, - IMultiPageFormService multiPageFormService + IMultiPageFormService multiPageFormService, + IRegistrationService registrationService ) { this.supervisorService = supervisorService; @@ -52,7 +54,8 @@ IMultiPageFormService multiPageFormService this.config = config; this.searchSortFilterPaginateService = searchSortFilterPaginateService; this.multiPageFormService = multiPageFormService; - } + this.registrationService = registrationService; + } private int GetCentreId() { diff --git a/DigitalLearningSolutions.Web/ViewModels/Supervisor/SupervisorDelegateViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Supervisor/SupervisorDelegateViewModel.cs index 07bec803c8..b2bf4e0f39 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Supervisor/SupervisorDelegateViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Supervisor/SupervisorDelegateViewModel.cs @@ -15,9 +15,7 @@ public SupervisorDelegateViewModel(SupervisorDelegateDetail detail, ReturnPageQu CandidateAssessmentCount = detail.CandidateAssessmentCount; ReturnPageQuery = returnPageQuery; } - public SupervisorDelegateViewModel() { } - public int Id { get; set; } public string? FirstName { get; set; } public string? LastName { get; set; } @@ -25,7 +23,7 @@ public SupervisorDelegateViewModel() { } public string DelegateEmail { get; set; } public ReturnPageQuery ReturnPageQuery { get; set; } - [BooleanMustBeTrue(ErrorMessage = "Confirm you wish to remove this staff member")] - public bool ConfirmedRemove { get; set; } + [BooleanMustBeTrue(ErrorMessage = "Please tick the checkbox to confirm you wish to perform this action")] + public bool ActionConfirmed { get; set; } } } diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/NominateSupervisor.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/NominateSupervisor.cshtml new file mode 100644 index 0000000000..f1858176c1 --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/Supervisor/NominateSupervisor.cshtml @@ -0,0 +1,55 @@ +@using DigitalLearningSolutions.Web.ViewModels.Supervisor +@using Microsoft.Extensions.Configuration +@model SupervisorDelegateViewModel; +@inject IConfiguration Configuration; +@{ + var errorHasOccurred = !ViewData.ModelState.IsValid; + ViewData["Application"] = "Supervisor"; + ViewData["Title"] = (errorHasOccurred ? "Error: " : "") + "My Staff - Nominate Supervisor"; + ViewData["HeaderPath"] = $"{Configuration["AppRootPath"]}/Supervisor/MyStaff"; + ViewData["HeaderPathName"] = "My Staff"; +} + +@section NavMenuItems { + +} + +
+
+ @if (errorHasOccurred) + { + + } +

Confirm Nominate Supervisor

+
+
+
+ Staff member: +
+
+
+ @Model.FirstName @Model.LastName (@Model.DelegateEmail) +
+
+

By nominating this member of staff as a supervisor, you are confirming there competence to assess the capability of others.

+

Once the nominated supervisor role has been assigned, it can only be removed by a Centre Manager or Clinical Centre Manager.

+
+
+ +
+ + @Html.HiddenFor(m => m.Id) + @Html.HiddenFor(m => m.FirstName) + @Html.HiddenFor(m => m.LastName) + @Html.HiddenFor(m => m.DelegateEmail) + @Html.HiddenFor(m => m.CandidateAssessmentCount) + @Html.HiddenFor(m => m.ReturnPageQuery) +
+ + +
+
diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/RemoveConfirm.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/RemoveConfirm.cshtml index 3d299c67c6..6c117c52dd 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/RemoveConfirm.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/RemoveConfirm.cshtml @@ -18,7 +18,7 @@
@if (errorHasOccurred) { - + }

Confirm Remove Staff Member

@@ -34,7 +34,7 @@

You are supervising @Model.CandidateAssessmentCount profile assessments for this member of staff.

-
diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffDetails.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffDetails.cshtml index e26fc40883..1abebbb963 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffDetails.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffDetails.cshtml @@ -2,119 +2,118 @@ @using DigitalLearningSolutions.Web.Extensions @model SupervisorDelegateDetail @{ - bool IsSupervisor = (bool)(ViewData["isSupervisor"] ?? false); + bool IsSupervisor = (bool)(ViewData["isSupervisor"] ?? false); }
-
-
- Added -
-
- @(Model.Added.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.Added.ToShortDateString() : "Today") -
-
-
-
- @if (IsSupervisor) - {
-
- PRN -
-
- @(Model.ProfessionalRegistrationNumber == null ? "Not Recorded" : Model.ProfessionalRegistrationNumber) -
+
+ Added +
+
+ @(Model.Added.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.Added.ToShortDateString() : "Today") +
- } -
-
- ID -
-
- @Model.CandidateNumber -
-
-
-
- Job Group -
-
- @Model.JobGroupName -
-
- @if (Model.CustomPrompt1 != null) - { + @if (IsSupervisor) + { +
+
+ PRN +
+
+ @(Model.ProfessionalRegistrationNumber == null ? "Not Recorded" : Model.ProfessionalRegistrationNumber) +
+
+ }
-
- @Model.CustomPrompt1 -
-
- @Model.Answer1 -
+
+ ID +
+
+ @Model.CandidateNumber +
- } - @if (Model.CustomPrompt2 != null) - {
-
- @Model.CustomPrompt2 -
-
- @Model.Answer2 -
+
+ Job Group +
+
+ @Model.JobGroupName +
- } - @if (Model.CustomPrompt3 != null) - { + @if (Model.CustomPrompt1 != null) + { +
+
+ @Model.CustomPrompt1 +
+
+ @Model.Answer1 +
+
+ } + @if (Model.CustomPrompt2 != null) + { +
+
+ @Model.CustomPrompt2 +
+
+ @Model.Answer2 +
+
+ } + @if (Model.CustomPrompt3 != null) + { +
+
+ @Model.CustomPrompt3 +
+
+ @Model.Answer3 +
+
+ } + @if (Model.CustomPrompt4 != null) + { +
+
+ @Model.CustomPrompt4 +
+
+ @Model.Answer4 +
+
+ } + @if (Model.CustomPrompt5 != null) + { +
+
+ @Model.CustomPrompt5 +
+
+ @Model.Answer5 +
+
+ } + @if (Model.CustomPrompt6 != null) + { +
+
+ @Model.CustomPrompt6 +
+
+ @Model.Answer6 +
+
+ }
-
- @Model.CustomPrompt3 -
-
- @Model.Answer3 -
-
- } - @if (Model.CustomPrompt4 != null) - { -
-
- @Model.CustomPrompt4 -
-
- @Model.Answer4 -
-
- } - @if (Model.CustomPrompt5 != null) - { -
-
- @Model.CustomPrompt5 -
-
- @Model.Answer5 -
-
- } - @if (Model.CustomPrompt6 != null) - { -
-
- @Model.CustomPrompt6 -
-
- @Model.Answer6 -
+
+ DLS Role +
+
+ @Model.DlsRole.GetDescription() + +
- } -
-
- DLS Role -
-
- @Model.DlsRole.GetDescription() -
-
diff --git a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffMemberCard.cshtml b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffMemberCard.cshtml index ed2b234c2f..f8f6c53a4d 100644 --- a/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffMemberCard.cshtml +++ b/DigitalLearningSolutions.Web/Views/Supervisor/Shared/_StaffMemberCard.cshtml @@ -1,119 +1,130 @@ -@using DigitalLearningSolutions.Web.ViewModels.Supervisor +@using DigitalLearningSolutions.Data.Enums +@using DigitalLearningSolutions.Web.ViewModels.Supervisor @model SupervisorDelegateDetailViewModel;
-
- +
+ - @if (Model.SupervisorDelegateDetail.CandidateID == null) - { -
-
- - @Model.SupervisorDelegateDetail.DelegateEmail - -
-
- - - Not registered - - -
-
- } - else - { -
-
- - @Model.SupervisorDelegateDetail.FirstName @Model.SupervisorDelegateDetail.LastName (@Model.SupervisorDelegateDetail.DelegateEmail) - -
-
- } + @if (Model.SupervisorDelegateDetail.CandidateID == null) + { +
+
+ + @Model.SupervisorDelegateDetail.DelegateEmail + +
+
+ + + Not registered + + +
+
+ } + else + { +
+
+ + @Model.SupervisorDelegateDetail.FirstName @Model.SupervisorDelegateDetail.LastName (@Model.SupervisorDelegateDetail.DelegateEmail) + +
+
+ } -
-
-
- @if (Model.SupervisorDelegateDetail.CandidateID == null) - { -
-
-
- Added -
-
- @(Model.SupervisorDelegateDetail.Added.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.SupervisorDelegateDetail.Added.ToShortDateString() : "Today") -
-
-
-
-
-
- Notification Sent -
-
- @(Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() : "Today") -
-
- @if (Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() != DateTime.UtcNow.ToShortDateString()) +
+
+
+ @if (Model.SupervisorDelegateDetail.CandidateID == null) + { +
+
+
+ Added +
+
+ @(Model.SupervisorDelegateDetail.Added.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.SupervisorDelegateDetail.Added.ToShortDateString() : "Today") +
+
+
+
+
+
+ Notification Sent +
+
+ @(Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() != DateTime.UtcNow.ToShortDateString() ? Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() : "Today") +
+
+ @if (Model.SupervisorDelegateDetail.NotificationSent.ToShortDateString() != DateTime.UtcNow.ToShortDateString()) + { + + Send reminder + + } +
+
+
+ } + else + { + + } +
+ @if (Model.SupervisorDelegateDetail.DlsRole == DlsRole.Learner && Model.IsUserSupervisor) + { + + Nominate supervisor + + } + @if (Model.SupervisorDelegateDetail.CandidateAssessmentCount == 0) { - - Send reminder - + + + @Html.Hidden("Id", Model.SupervisorDelegateDetail.ID) + @Html.Hidden("DelegateEmail", Model.SupervisorDelegateDetail.DelegateEmail) + @Html.Hidden("ConfirmedRemove", true) + @Html.HiddenFor(m => m.ReturnPageQuery) + + } + else + { + + Remove staff member + } -
- - } - else - { - - } -
- @if (Model.SupervisorDelegateDetail.CandidateAssessmentCount == 0) - { -
- - @Html.Hidden("Id", Model.SupervisorDelegateDetail.ID) - @Html.Hidden("DelegateEmail", Model.SupervisorDelegateDetail.DelegateEmail) - @Html.Hidden("ConfirmedRemove", true) - @Html.HiddenFor(m => m.ReturnPageQuery) -
- } - else - { - - Remove staff member + + @if (Model.SupervisorDelegateDetail.CandidateID != null) + { + + View self assessments (@Model.SupervisorDelegateDetail.CandidateAssessmentCount) - } -
- - @if (Model.SupervisorDelegateDetail.CandidateID != null) - { - - View self assessments (@Model.SupervisorDelegateDetail.CandidateAssessmentCount) - - } - else if (Model.SupervisorDelegateDetail.AddedByDelegate) - { + } + else if (Model.SupervisorDelegateDetail.AddedByDelegate) + { - Confirm + aria-describedby="@Model.SupervisorDelegateDetail.ID-name" + asp-controller="Supervisor" + asp-action="ConfirmSupervise" + asp-route-supervisorDelegateId="@Model.SupervisorDelegateDetail.ID"> + Confirm - } + }