From 61e656d0a8972e889b4b41150575a8e89acbc43b Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Tue, 13 Jul 2021 16:49:35 +0100 Subject: [PATCH 1/9] HEEDLS-547 Delegate registration by centre: Confirmation page --- .../RegisterDelegateByCentreController.cs | 27 +++++++++++- .../ConfirmationViewModel.cs | 16 +++++++ .../Confirmation.cshtml | 43 +++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 DigitalLearningSolutions.Web/ViewModels/RegisterDelegateByCentre/ConfirmationViewModel.cs create mode 100644 DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml diff --git a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs index 2cf745a4fc..13a2d8f6f0 100644 --- a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs +++ b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs @@ -17,6 +17,8 @@ namespace DigitalLearningSolutions.Web.Controllers.Register using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.FeatureManagement.Mvc; + using ConfirmationViewModel = + DigitalLearningSolutions.Web.ViewModels.RegisterDelegateByCentre.ConfirmationViewModel; using PasswordViewModel = DigitalLearningSolutions.Web.ViewModels.RegisterDelegateByCentre.PasswordViewModel; using SummaryViewModel = DigitalLearningSolutions.Web.ViewModels.RegisterDelegateByCentre.SummaryViewModel; @@ -202,7 +204,30 @@ public IActionResult Summary() [HttpPost] public IActionResult Summary(SummaryViewModel model) { - return new OkResult(); + var data = TempData.Peek()!; + + // TODO: actually register the delegate + + TempData.Clear(); + TempData.Add("delegateNumber", "XY1234"); + TempData.Add("emailSent", data.ShouldSendEmail); + TempData.Add("passwordSet", data.IsPasswordSet); + return RedirectToAction("Confirmation"); + } + + [HttpGet] + public IActionResult Confirmation() + { + var delegateNumber = (string?)TempData.Peek("delegateNumber"); + var emailSent = (bool)TempData.Peek("emailSent"); + var passwordSet = (bool)TempData.Peek("passwordSet"); + if (delegateNumber == null) + { + return RedirectToAction("Index"); + } + + var viewModel = new ConfirmationViewModel(delegateNumber, emailSent, passwordSet); + return View(viewModel); } private void SetCentreDelegateRegistrationData(int centreId) diff --git a/DigitalLearningSolutions.Web/ViewModels/RegisterDelegateByCentre/ConfirmationViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/RegisterDelegateByCentre/ConfirmationViewModel.cs new file mode 100644 index 0000000000..030aedae98 --- /dev/null +++ b/DigitalLearningSolutions.Web/ViewModels/RegisterDelegateByCentre/ConfirmationViewModel.cs @@ -0,0 +1,16 @@ +namespace DigitalLearningSolutions.Web.ViewModels.RegisterDelegateByCentre +{ + public class ConfirmationViewModel + { + public ConfirmationViewModel(string delegateNumber, bool emailSent, bool passwordSet) + { + DelegateNumber = delegateNumber; + EmailSent = emailSent; + PasswordSet = passwordSet; + } + + public string DelegateNumber { get; set; } + public bool EmailSent { get; set; } + public bool PasswordSet { get; set; } + } +} diff --git a/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml b/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml new file mode 100644 index 0000000000..a6b1ffc9ff --- /dev/null +++ b/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml @@ -0,0 +1,43 @@ +@inject IConfiguration Configuration +@using DigitalLearningSolutions.Web.ViewModels.RegisterDelegateByCentre +@using Microsoft.Extensions.Configuration +@model ConfirmationViewModel + +@{ + ViewData["Title"] = "Register Delegate - Confirmation"; + ViewData["Application"] = "Tracking System"; + ViewData["HeaderPath"] = $"{Configuration["AppRootPath"]}/TrackingSystem/Centre/Dashboard"; + ViewData["HeaderPathName"] = "Tracking System"; +} + +@section NavMenuItems { + +} + +
+
+

+ Delegate registration complete +

+ @if (Model.EmailSent) { +

+ A welcome message will be sent to the email address provided, on the date specified, inviting the delegate to set their password and confirm their registration. +

+ } else { + if (Model.PasswordSet) { +

+ You should contact the delegate to inform them of their login details and recommend that they change their password using the My account interface after login. +

+ } else { +

+ The delegate has been registered but no welcome email has been sent. You can send the welcome email at a later date from the All Delegates interface using the Send Welcome Emails button. +

+ } + } +
+ Information: +

Delegate number @Model.DelegateNumber

+
+ +
+
From 0bf469ca497e88511231757b7107d6881d610983 Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Tue, 13 Jul 2021 17:45:48 +0100 Subject: [PATCH 2/9] HEEDLS-547 Implement service methods to for delegate registration by centre; update DelegateRegistrationModel --- .../DataServices/RegistrationDataService.cs | 33 +++++++++++++++++++ .../Register/DelegateRegistrationModel.cs | 6 ++++ .../Services/RegistrationService.cs | 15 +++++++++ 3 files changed, 54 insertions(+) diff --git a/DigitalLearningSolutions.Data/DataServices/RegistrationDataService.cs b/DigitalLearningSolutions.Data/DataServices/RegistrationDataService.cs index eabc54dc3e..b90a69b955 100644 --- a/DigitalLearningSolutions.Data/DataServices/RegistrationDataService.cs +++ b/DigitalLearningSolutions.Data/DataServices/RegistrationDataService.cs @@ -9,6 +9,7 @@ public interface IRegistrationDataService { string RegisterDelegate(DelegateRegistrationModel delegateRegistrationModel); + string RegisterDelegateByCentre(DelegateRegistrationModel delegateRegistrationModel); int RegisterCentreManagerAdmin(RegistrationModel registrationModel); } @@ -53,6 +54,38 @@ public string RegisterDelegate(DelegateRegistrationModel delegateRegistrationMod return candidateNumber; } + public string RegisterDelegateByCentre(DelegateRegistrationModel delegateRegistrationModel) + { + var values = new + { + delegateRegistrationModel.FirstName, + delegateRegistrationModel.LastName, + delegateRegistrationModel.Email, + CentreID = delegateRegistrationModel.Centre, + JobGroupID = delegateRegistrationModel.JobGroup, + Active = 1, + Approved = 1, + delegateRegistrationModel.Answer1, + delegateRegistrationModel.Answer2, + delegateRegistrationModel.Answer3, + delegateRegistrationModel.Answer4, + delegateRegistrationModel.Answer5, + delegateRegistrationModel.Answer6, + AliasID = delegateRegistrationModel.AliasId, + ExternalReg = 0, + SelfReg = 0, + delegateRegistrationModel.NotifyDate, + Bulk = 0 + }; + + var candidateNumber = connection.QueryFirstOrDefault( + "uspSaveNewCandidate_V10", + values, + commandType: CommandType.StoredProcedure); + + return candidateNumber; + } + public int RegisterCentreManagerAdmin(RegistrationModel registrationModel) { var values = new diff --git a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs index 3d2cdc736e..9b9bcce442 100644 --- a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs +++ b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs @@ -1,5 +1,7 @@ namespace DigitalLearningSolutions.Data.Models.Register { + using System; + public class DelegateRegistrationModel : RegistrationModel { public DelegateRegistrationModel( @@ -44,5 +46,9 @@ string passwordHash public string? Answer5 { get; set; } public string? Answer6 { get; set; } + + public string? AliasId { get; set; } + + public DateTime? NotifyDate { get; set; } } } diff --git a/DigitalLearningSolutions.Data/Services/RegistrationService.cs b/DigitalLearningSolutions.Data/Services/RegistrationService.cs index 48f6db1fdc..0d0f7b2d2c 100644 --- a/DigitalLearningSolutions.Data/Services/RegistrationService.cs +++ b/DigitalLearningSolutions.Data/Services/RegistrationService.cs @@ -17,6 +17,8 @@ public interface IRegistrationService bool refactoredTrackingSystemEnabled ); + string RegisterDelegateByCentre(DelegateRegistrationModel delegateRegistrationModel); + void RegisterCentreManager(RegistrationModel registrationModel); } @@ -81,6 +83,19 @@ bool refactoredTrackingSystemEnabled return (candidateNumber, delegateRegistrationModel.Approved); } + public string RegisterDelegateByCentre(DelegateRegistrationModel delegateRegistrationModel) + { + var candidateNumber = registrationDataService.RegisterDelegateByCentre(delegateRegistrationModel); + if (candidateNumber == "-1" || candidateNumber == "-4") + { + return candidateNumber; + } + + passwordDataService.SetPasswordByCandidateNumber(candidateNumber, delegateRegistrationModel.PasswordHash); + + return candidateNumber; + } + public void RegisterCentreManager(RegistrationModel registrationModel) { using var transaction = new TransactionScope(); From c9ad2be27087fdf0744c0642d0bb8fe9764c32d6 Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Tue, 13 Jul 2021 17:46:26 +0100 Subject: [PATCH 3/9] HEEDLS-547 Register delegate on Summary POST; update mapping helper; update test --- ...RegisterDelegateByCentreControllerTests.cs | 4 +++- .../RegisterDelegateByCentreController.cs | 20 ++++++++++++++++--- .../Helpers/RegistrationMappingHelper.cs | 18 +++++++++++++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs index 752b4f1480..21b9a83850 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs @@ -23,6 +23,7 @@ public class RegisterDelegateByCentreControllerTests private IUserDataService userDataService = null!; private IUserService userService = null!; private ICryptoService cryptoService = null!; + private IRegistrationService registrationService = null!; [SetUp] public void Setup() @@ -32,12 +33,13 @@ public void Setup() userDataService = A.Fake(); customPromptHelper = A.Fake(); cryptoService = A.Fake(); + registrationService = A.Fake(); controller = new RegisterDelegateByCentreController( jobGroupsDataService, userService, customPromptHelper, cryptoService, - userDataService + userDataService,registrationService ) .WithDefaultContext() .WithMockTempData(); diff --git a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs index 13a2d8f6f0..3500c8ce42 100644 --- a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs +++ b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs @@ -31,6 +31,7 @@ public class RegisterDelegateByCentreController : Controller private readonly ICryptoService cryptoService; private readonly CustomPromptHelper customPromptHelper; private readonly IJobGroupsDataService jobGroupsDataService; + private readonly IRegistrationService registrationService; private readonly IUserDataService userDataService; private readonly IUserService userService; @@ -39,13 +40,15 @@ public RegisterDelegateByCentreController( IUserService userService, CustomPromptHelper customPromptHelper, ICryptoService cryptoService, - IUserDataService userDataService + IUserDataService userDataService, + IRegistrationService registrationService ) { this.jobGroupsDataService = jobGroupsDataService; this.userService = userService; this.customPromptHelper = customPromptHelper; this.userDataService = userDataService; + this.registrationService = registrationService; this.cryptoService = cryptoService; } @@ -206,10 +209,21 @@ public IActionResult Summary(SummaryViewModel model) { var data = TempData.Peek()!; - // TODO: actually register the delegate + var candidateNumber = + registrationService.RegisterDelegateByCentre( + RegistrationMappingHelper.MapToDelegateRegistrationModel(data) + ); + + switch (candidateNumber) + { + case "-1": + return RedirectToAction("Error", "LearningSolutions"); + case "-4": + return RedirectToAction("Index"); + } TempData.Clear(); - TempData.Add("delegateNumber", "XY1234"); + TempData.Add("delegateNumber", candidateNumber); TempData.Add("emailSent", data.ShouldSendEmail); TempData.Add("passwordSet", data.IsPasswordSet); return RedirectToAction("Confirmation"); diff --git a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs index 2e27a109a8..6f2131011e 100644 --- a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs @@ -34,5 +34,23 @@ public static DelegateRegistrationModel MapToDelegateRegistrationModel(DelegateR data.Answer6 ); } + + public static DelegateRegistrationModel MapToDelegateRegistrationModel(DelegateRegistrationByCentreData data) + { + return new DelegateRegistrationModel( + data.FirstName!, + data.LastName!, + data.Email!, + data.Centre!.Value, + data.JobGroup!.Value, + data.PasswordHash!, + data.Answer1, + data.Answer2, + data.Answer3, + data.Answer4, + data.Answer5, + data.Answer6 + ) {AliasId = data.Alias, NotifyDate = data.WelcomeEmailDate}; + } } } From 6f9308a849a4ec28b47520d2b87d7e055f2c2aab Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Tue, 13 Jul 2021 18:09:01 +0100 Subject: [PATCH 4/9] HEEDLS-547 Only set pwd in database if needed; make passwordHash nullable in RegistrationModel --- .../Models/Register/DelegateRegistrationModel.cs | 2 +- .../Models/Register/RegistrationModel.cs | 4 ++-- .../Services/RegistrationService.cs | 8 +++++++- .../Helpers/RegistrationMappingHelper.cs | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs index 9b9bcce442..f38516c4ba 100644 --- a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs +++ b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs @@ -10,7 +10,7 @@ public DelegateRegistrationModel( string email, int centre, int jobGroup, - string passwordHash, + string? passwordHash, string? answer1, string? answer2, string? answer3, diff --git a/DigitalLearningSolutions.Data/Models/Register/RegistrationModel.cs b/DigitalLearningSolutions.Data/Models/Register/RegistrationModel.cs index 6d745db4e2..b0db835fd1 100644 --- a/DigitalLearningSolutions.Data/Models/Register/RegistrationModel.cs +++ b/DigitalLearningSolutions.Data/Models/Register/RegistrationModel.cs @@ -8,7 +8,7 @@ public RegistrationModel( string email, int centre, int jobGroup, - string passwordHash + string? passwordHash ) { FirstName = firstName; @@ -30,7 +30,7 @@ string passwordHash public int JobGroup { get; set; } - public string PasswordHash { get; set; } + public string? PasswordHash { get; set; } public bool Approved { get; set; } } diff --git a/DigitalLearningSolutions.Data/Services/RegistrationService.cs b/DigitalLearningSolutions.Data/Services/RegistrationService.cs index 0d0f7b2d2c..ad44e39c16 100644 --- a/DigitalLearningSolutions.Data/Services/RegistrationService.cs +++ b/DigitalLearningSolutions.Data/Services/RegistrationService.cs @@ -91,7 +91,13 @@ public string RegisterDelegateByCentre(DelegateRegistrationModel delegateRegistr return candidateNumber; } - passwordDataService.SetPasswordByCandidateNumber(candidateNumber, delegateRegistrationModel.PasswordHash); + if (delegateRegistrationModel.PasswordHash != null) + { + passwordDataService.SetPasswordByCandidateNumber( + candidateNumber, + delegateRegistrationModel.PasswordHash + ); + } return candidateNumber; } diff --git a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs index 6f2131011e..ac61a6eac8 100644 --- a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs @@ -43,7 +43,7 @@ public static DelegateRegistrationModel MapToDelegateRegistrationModel(DelegateR data.Email!, data.Centre!.Value, data.JobGroup!.Value, - data.PasswordHash!, + data.IsPasswordSet ? data.PasswordHash! : null, data.Answer1, data.Answer2, data.Answer3, From 7b6615c35350ea0dc9be3635991c6cb6bcaa596b Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Wed, 14 Jul 2021 17:27:52 +0100 Subject: [PATCH 5/9] HEEDLS-547 Supress pwHash null warnings; add fields to DRModel constructor; rename EmailSent for clarity --- .../Models/Register/DelegateRegistrationModel.cs | 7 ++++++- .../Services/RegistrationService.cs | 6 +++--- .../Helpers/RegistrationMappingHelper.cs | 6 ++++-- .../RegisterDelegateByCentre/ConfirmationViewModel.cs | 6 +++--- .../Views/RegisterDelegateByCentre/Confirmation.cshtml | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs index f38516c4ba..9e42111c7a 100644 --- a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs +++ b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs @@ -16,7 +16,10 @@ public DelegateRegistrationModel( string? answer3, string? answer4, string? answer5, - string? answer6) : base(firstName, lastName, email, centre, jobGroup, passwordHash) + string? answer6, + string? aliasId = null, + DateTime? notifyDate = null + ) : base(firstName, lastName, email, centre, jobGroup, passwordHash) { Answer1 = answer1; Answer2 = answer2; @@ -24,6 +27,8 @@ public DelegateRegistrationModel( Answer4 = answer4; Answer5 = answer5; Answer6 = answer6; + AliasId = aliasId; + NotifyDate = notifyDate; } public DelegateRegistrationModel( diff --git a/DigitalLearningSolutions.Data/Services/RegistrationService.cs b/DigitalLearningSolutions.Data/Services/RegistrationService.cs index ad44e39c16..e1fdd74027 100644 --- a/DigitalLearningSolutions.Data/Services/RegistrationService.cs +++ b/DigitalLearningSolutions.Data/Services/RegistrationService.cs @@ -65,7 +65,7 @@ bool refactoredTrackingSystemEnabled passwordDataService.SetPasswordByCandidateNumber( candidateNumber, - delegateRegistrationModel.PasswordHash + delegateRegistrationModel.PasswordHash! ); if (!delegateRegistrationModel.Approved) { @@ -123,7 +123,7 @@ private void CreateDelegateAccountForAdmin(RegistrationModel registrationModel) registrationModel.Email, registrationModel.Centre, registrationModel.JobGroup, - registrationModel.PasswordHash + registrationModel.PasswordHash! ) { Approved = true }; var candidateNumber = registrationDataService.RegisterDelegate(delegateRegistrationModel); @@ -136,7 +136,7 @@ private void CreateDelegateAccountForAdmin(RegistrationModel registrationModel) passwordDataService.SetPasswordByCandidateNumber( candidateNumber, - delegateRegistrationModel.PasswordHash + delegateRegistrationModel.PasswordHash! ); } diff --git a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs index ac61a6eac8..43f4a3f7cd 100644 --- a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs @@ -49,8 +49,10 @@ public static DelegateRegistrationModel MapToDelegateRegistrationModel(DelegateR data.Answer3, data.Answer4, data.Answer5, - data.Answer6 - ) {AliasId = data.Alias, NotifyDate = data.WelcomeEmailDate}; + data.Answer6, + data.Alias, + data.WelcomeEmailDate + ); } } } diff --git a/DigitalLearningSolutions.Web/ViewModels/Register/RegisterDelegateByCentre/ConfirmationViewModel.cs b/DigitalLearningSolutions.Web/ViewModels/Register/RegisterDelegateByCentre/ConfirmationViewModel.cs index 02334131e0..2dbc04b332 100644 --- a/DigitalLearningSolutions.Web/ViewModels/Register/RegisterDelegateByCentre/ConfirmationViewModel.cs +++ b/DigitalLearningSolutions.Web/ViewModels/Register/RegisterDelegateByCentre/ConfirmationViewModel.cs @@ -2,15 +2,15 @@ { public class ConfirmationViewModel { - public ConfirmationViewModel(string delegateNumber, bool emailSent, bool passwordSet) + public ConfirmationViewModel(string delegateNumber, bool emailWillBeSent, bool passwordSet) { DelegateNumber = delegateNumber; - EmailSent = emailSent; + EmailWillBeSent = emailWillBeSent; PasswordSet = passwordSet; } public string DelegateNumber { get; set; } - public bool EmailSent { get; set; } + public bool EmailWillBeSent { get; set; } public bool PasswordSet { get; set; } } } diff --git a/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml b/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml index 68e7dd4e93..a9104ee68d 100644 --- a/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml +++ b/DigitalLearningSolutions.Web/Views/RegisterDelegateByCentre/Confirmation.cshtml @@ -19,7 +19,7 @@

Delegate registration complete

- @if (Model.EmailSent) { + @if (Model.EmailWillBeSent) {

A welcome message will be sent to the email address provided, on the date specified, inviting the delegate to set their password and confirm their registration.

From 6343b355cceb038e5e1e66ef0cd30650bb831a8b Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Wed, 14 Jul 2021 18:03:19 +0100 Subject: [PATCH 6/9] HEEDLS-547 Add RegistrationService tests for password setting when registering delegate by centre --- .../Services/RegistrationServiceTests.cs | 30 +++++++++++++++++++ .../Register/DelegateRegistrationModel.cs | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs b/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs index 9b4d0c68be..8511437b4f 100644 --- a/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs +++ b/DigitalLearningSolutions.Data.Tests/Services/RegistrationServiceTests.cs @@ -346,5 +346,35 @@ public void Error_in_RegisterCentreManager_fails_fast() A.CallTo(() => centresDataService.SetCentreAutoRegistered(testRegistrationModel.Centre)) .MustNotHaveHappened(); } + + [Test] + public void RegisterDelegateByCentre_sets_password_if_passwordHash_not_null() + { + // Given + var model = new DelegateRegistrationModel("firstName", "lastName", "email", 0, 0, PasswordHash); + A.CallTo(() => registrationDataService.RegisterDelegateByCentre(model)).Returns(NewCandidateNumber); + + // When + registrationService.RegisterDelegateByCentre(model); + + // Then + A.CallTo(() => registrationDataService.RegisterDelegateByCentre(model)).MustHaveHappened(1, Times.Exactly); + A.CallTo(() => passwordDataService.SetPasswordByCandidateNumber(NewCandidateNumber, PasswordHash)).MustHaveHappened(1, Times.Exactly); + } + + [Test] + public void RegisterDelegateByCentre_does_not_set_password_if_passwordHash_is_null() + { + // Given + var model = new DelegateRegistrationModel("firstName", "lastName", "email", 0, 0, null); + A.CallTo(() => registrationDataService.RegisterDelegateByCentre(model)).Returns(NewCandidateNumber); + + // When + registrationService.RegisterDelegateByCentre(model); + + // Then + A.CallTo(() => registrationDataService.RegisterDelegateByCentre(model)).MustHaveHappened(1, Times.Exactly); + A.CallTo(() => passwordDataService.SetPasswordByCandidateNumber(A._, A._)).MustNotHaveHappened(); + } } } diff --git a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs index 9e42111c7a..071cc70148 100644 --- a/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs +++ b/DigitalLearningSolutions.Data/Models/Register/DelegateRegistrationModel.cs @@ -37,7 +37,7 @@ public DelegateRegistrationModel( string email, int centre, int jobGroup, - string passwordHash + string? passwordHash ) : base(firstName, lastName, email, centre, jobGroup, passwordHash) { } public string? Answer1 { get; set; } From 5d8153bffdadd2e9fe09448f497380c0f9e93e16 Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Thu, 15 Jul 2021 14:44:45 +0100 Subject: [PATCH 7/9] HEEDLS-547 review markups --- .../Register/RegisterDelegateByCentreControllerTests.cs | 7 ++++--- .../Register/RegisterDelegateByCentreController.cs | 3 ++- .../Helpers/RegistrationMappingHelper.cs | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs index 21b9a83850..cb4d308a9a 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs @@ -18,12 +18,12 @@ public class RegisterDelegateByCentreControllerTests { private RegisterDelegateByCentreController controller = null!; + private ICryptoService cryptoService = null!; private CustomPromptHelper customPromptHelper = null!; private IJobGroupsDataService jobGroupsDataService = null!; + private IRegistrationService registrationService = null!; private IUserDataService userDataService = null!; private IUserService userService = null!; - private ICryptoService cryptoService = null!; - private IRegistrationService registrationService = null!; [SetUp] public void Setup() @@ -39,7 +39,8 @@ public void Setup() userService, customPromptHelper, cryptoService, - userDataService,registrationService + userDataService, + registrationService ) .WithDefaultContext() .WithMockTempData(); diff --git a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs index 11ce7908ff..f3b216cdd3 100644 --- a/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs +++ b/DigitalLearningSolutions.Web/Controllers/Register/RegisterDelegateByCentreController.cs @@ -218,7 +218,7 @@ public IActionResult Summary(SummaryViewModel model) switch (candidateNumber) { case "-1": - return RedirectToAction("Error", "LearningSolutions"); + return StatusCode(500); case "-4": return RedirectToAction("Index"); } @@ -236,6 +236,7 @@ public IActionResult Confirmation() var delegateNumber = (string?)TempData.Peek("delegateNumber"); var emailSent = (bool)TempData.Peek("emailSent"); var passwordSet = (bool)TempData.Peek("passwordSet"); + TempData.Clear(); if (delegateNumber == null) { return RedirectToAction("Index"); diff --git a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs index 43f4a3f7cd..f5d45b0132 100644 --- a/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs +++ b/DigitalLearningSolutions.Web/Helpers/RegistrationMappingHelper.cs @@ -43,7 +43,7 @@ public static DelegateRegistrationModel MapToDelegateRegistrationModel(DelegateR data.Email!, data.Centre!.Value, data.JobGroup!.Value, - data.IsPasswordSet ? data.PasswordHash! : null, + data.PasswordHash, data.Answer1, data.Answer2, data.Answer3, From 84f8973a4793287baf6905d8ccdb8ccce1dc9999 Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Thu, 15 Jul 2021 15:54:16 +0100 Subject: [PATCH 8/9] HEEDLS-547 Write automated UI tests for RegisterDelegateByCentre journey --- .../RegistrationJourneyAccessibilityTests.cs | 80 ++++++++++++++++++- .../TestHelpers/DriverHelper.cs | 9 +++ 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/RegistrationJourneyAccessibilityTests.cs b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/RegistrationJourneyAccessibilityTests.cs index dee9d2edd2..44487ff557 100644 --- a/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/RegistrationJourneyAccessibilityTests.cs +++ b/DigitalLearningSolutions.Web.AutomatedUiTests/AccessibilityTests/RegistrationJourneyAccessibilityTests.cs @@ -2,8 +2,6 @@ { using DigitalLearningSolutions.Web.AutomatedUiTests.TestHelpers; using FluentAssertions; - using OpenQA.Selenium; - using OpenQA.Selenium.Support.UI; using Selenium.Axe; using Xunit; @@ -45,5 +43,83 @@ public void Registration_journey_has_no_accessibility_errors() passwordResult.Violations.Should().BeEmpty(); summaryResult.Violations.Should().BeEmpty(); } + + [Fact] + public void Registration_by_centre_journey_with_send_email_has_no_accessibility_errors() + { + // given + Driver.LogUserInAsAdminAndDelegate(BaseUrl); + const string registerUrl = "/TrackingSystem/Delegates/Register"; + + // when + Driver.Navigate().GoToUrl(BaseUrl + registerUrl); + var registerResult = new AxeBuilder(Driver).Analyze(); + Driver.FillTextInput("FirstName", "Test"); + Driver.FillTextInput("LastName", "User"); + Driver.FillTextInput("Email", "candidate@test.com"); + Driver.FillTextInput("Alias", "candid8"); + Driver.SubmitForm(); + + var learnerInformationResult = new AxeBuilder(Driver).Analyze(); + Driver.SelectDropdownItemValue("Answer1", "Principal Relationship Manager"); + Driver.FillTextInput("Answer2", "A Person"); + Driver.SelectDropdownItemValue("JobGroup", "1"); + Driver.SubmitForm(); + + var welcomeEmailResult = new AxeBuilder(Driver).Analyze(); + Driver.SetCheckboxState("ShouldSendEmail", true); + Driver.FillTextInput("Day", "14"); + Driver.FillTextInput("Month", "7"); + Driver.FillTextInput("Year", "2222"); + Driver.SubmitForm(); + + var summaryResult = new AxeBuilder(Driver).Analyze(); + + // then + registerResult.Violations.Should().BeEmpty(); + learnerInformationResult.Violations.Should().BeEmpty(); + welcomeEmailResult.Violations.Should().BeEmpty(); + summaryResult.Violations.Should().BeEmpty(); + } + + [Fact] + public void Registration_by_centre_journey_with_set_password_has_no_accessibility_errors() + { + // given + Driver.LogUserInAsAdminAndDelegate(BaseUrl); + const string registerUrl = "/TrackingSystem/Delegates/Register"; + + // when + Driver.Navigate().GoToUrl(BaseUrl + registerUrl); + var registerResult = new AxeBuilder(Driver).Analyze(); + Driver.FillTextInput("FirstName", "Test"); + Driver.FillTextInput("LastName", "User"); + Driver.FillTextInput("Email", "candidate@test.com"); + Driver.FillTextInput("Alias", "candid8"); + Driver.SubmitForm(); + + var learnerInformationResult = new AxeBuilder(Driver).Analyze(); + Driver.SelectDropdownItemValue("Answer1", "Principal Relationship Manager"); + Driver.FillTextInput("Answer2", "A Person"); + Driver.SelectDropdownItemValue("JobGroup", "1"); + Driver.SubmitForm(); + + var welcomeEmailResult = new AxeBuilder(Driver).Analyze(); + Driver.SetCheckboxState("ShouldSendEmail", false); + Driver.SubmitForm(); + + var passwordResult = new AxeBuilder(Driver).Analyze(); + Driver.FillTextInput("Password", "password!1"); + Driver.SubmitForm(); + + var summaryResult = new AxeBuilder(Driver).Analyze(); + + // then + registerResult.Violations.Should().BeEmpty(); + learnerInformationResult.Violations.Should().BeEmpty(); + welcomeEmailResult.Violations.Should().BeEmpty(); + passwordResult.Violations.Should().BeEmpty(); + summaryResult.Violations.Should().BeEmpty(); + } } } diff --git a/DigitalLearningSolutions.Web.AutomatedUiTests/TestHelpers/DriverHelper.cs b/DigitalLearningSolutions.Web.AutomatedUiTests/TestHelpers/DriverHelper.cs index ad78d507f2..90d482d9b6 100644 --- a/DigitalLearningSolutions.Web.AutomatedUiTests/TestHelpers/DriverHelper.cs +++ b/DigitalLearningSolutions.Web.AutomatedUiTests/TestHelpers/DriverHelper.cs @@ -31,6 +31,15 @@ public static void SelectDropdownItemValue(this IWebDriver driver, string dropdo dropdown.SelectByValue(selectedValue); } + public static void SetCheckboxState(this IWebDriver driver, string inputId, bool checkState) + { + var answer = driver.FindElement(By.Id(inputId)); + if (answer.Selected != checkState) + { + answer.Click(); + } + } + public static void SubmitForm(this IWebDriver driver) { var selectPromptForm = driver.FindElement(By.TagName("form")); From 21999b23167bf4f5137f470e6c99d83a141f6e95 Mon Sep 17 00:00:00 2001 From: Ibrahim Munir-Zubair Date: Thu, 15 Jul 2021 17:24:25 +0100 Subject: [PATCH 9/9] HEEDLS-547 Write RDbyC controller tests for updating tempdata --- ...RegisterDelegateByCentreControllerTests.cs | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) diff --git a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs index cb4d308a9a..539aea67cd 100644 --- a/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs +++ b/DigitalLearningSolutions.Web.Tests/Controllers/Register/RegisterDelegateByCentreControllerTests.cs @@ -1,7 +1,9 @@ namespace DigitalLearningSolutions.Web.Tests.Controllers.Register { + using System; using System.Collections.Generic; using DigitalLearningSolutions.Data.DataServices; + using DigitalLearningSolutions.Data.Models.Register; using DigitalLearningSolutions.Data.Models.User; using DigitalLearningSolutions.Data.Services; using DigitalLearningSolutions.Data.Tests.TestHelpers; @@ -10,10 +12,14 @@ using DigitalLearningSolutions.Web.Helpers; using DigitalLearningSolutions.Web.Models; using DigitalLearningSolutions.Web.Tests.ControllerHelpers; + using DigitalLearningSolutions.Web.ViewModels.Common; using DigitalLearningSolutions.Web.ViewModels.Register; + using DigitalLearningSolutions.Web.ViewModels.Register.RegisterDelegateByCentre; using FakeItEasy; + using FluentAssertions; using FluentAssertions.AspNetCore.Mvc; using NUnit.Framework; + using SummaryViewModel = DigitalLearningSolutions.Web.ViewModels.Register.RegisterDelegateByCentre.SummaryViewModel; public class RegisterDelegateByCentreControllerTests { @@ -145,5 +151,170 @@ public void PersonalInformationPost_with_duplicate_alias_for_different_centre_is A.CallTo(() => userDataService.GetAllDelegateUsersByUsername(duplicateAlias)).MustHaveHappened(); result.Should().BeRedirectToActionResult().WithActionName("LearnerInformation"); } + + [Test] + public void PersonalInformationPost_updates_tempdata_correctly() + { + // Given + const string firstName = "Test"; + const string lastName = "User"; + const string email = "test@email.com"; + const string alias = "testuser"; + + controller.TempData.Set(new DelegateRegistrationByCentreData()); + var model = new PersonalInformationViewModel + { + FirstName = firstName, + LastName = lastName, + Email = email, + Alias = alias + }; + + // When + controller.PersonalInformation(model); + + // Then + var data = controller.TempData.Peek()!; + data.FirstName.Should().Be(firstName); + data.LastName.Should().Be(lastName); + data.Email.Should().Be(email); + data.Alias.Should().Be(alias); + } + + [Test] + public void LearnerInformationPost_updates_tempdata_correctly() + { + // Given + const int jobGroupId = 3; + const string answer1 = "answer1"; + const string answer2 = "answer2"; + const string answer3 = "answer3"; + const string answer4 = "answer4"; + const string answer5 = "answer5"; + const string answer6 = "answer6"; + + controller.TempData.Set(new DelegateRegistrationByCentreData { Centre = 1 }); + var model = new LearnerInformationViewModel + { + JobGroup = jobGroupId, + Answer1 = answer1, + Answer2 = answer2, + Answer3 = answer3, + Answer4 = answer4, + Answer5 = answer5, + Answer6 = answer6 + }; + + // When + controller.LearnerInformation(model); + + // Then + var data = controller.TempData.Peek()!; + data.JobGroup.Should().Be(jobGroupId); + data.Answer1.Should().Be(answer1); + data.Answer2.Should().Be(answer2); + data.Answer3.Should().Be(answer3); + data.Answer4.Should().Be(answer4); + data.Answer5.Should().Be(answer5); + data.Answer6.Should().Be(answer6); + } + + [Test] + public void WelcomeEmailPost_with_ShouldSendEmail_false_updates_tempdata_correctly() + { + // Given + controller.TempData.Set(new DelegateRegistrationByCentreData()); + var model = new WelcomeEmailViewModel { ShouldSendEmail = false, Day = 7, Month = 7, Year = 2200 }; + + // When + controller.WelcomeEmail(model); + + // Then + var data = controller.TempData.Peek()!; + data.ShouldSendEmail.Should().BeFalse(); + data.WelcomeEmailDate.Should().BeNull(); + } + + [Test] + public void WelcomeEmailPost_with_ShouldSendEmail_true_updates_tempdata_correctly() + { + // Given + controller.TempData.Set(new DelegateRegistrationByCentreData { PasswordHash = "hash" }); + var date = new DateTime(2200, 7, 7); + var model = new WelcomeEmailViewModel + { ShouldSendEmail = true, Day = date.Day, Month = date.Month, Year = date.Year }; + + // When + controller.WelcomeEmail(model); + + // Then + var data = controller.TempData.Peek()!; + data.ShouldSendEmail.Should().BeTrue(); + data.WelcomeEmailDate.Should().Be(date); + data.IsPasswordSet.Should().BeFalse(); + data.PasswordHash.Should().BeNull(); + } + + [Test] + public void PasswordPost_with_no_password_updates_tempdata_correctly() + { + // Given + controller.TempData.Set(new DelegateRegistrationByCentreData()); + var model = new PasswordViewModel { Password = null }; + A.CallTo(() => cryptoService.GetPasswordHash(A._)).Returns("hash"); + + // When + controller.Password(model); + + // Then + A.CallTo(() => cryptoService.GetPasswordHash(A._)).MustNotHaveHappened(); + var data = controller.TempData.Peek()!; + data.PasswordHash.Should().BeNull(); + } + + [Test] + public void PasswordPost_with_password_updates_tempdata_correctly() + { + // Given + controller.TempData.Set(new DelegateRegistrationByCentreData()); + var model = new PasswordViewModel { Password = "pwd" }; + const string passwordHash = "hash"; + A.CallTo(() => cryptoService.GetPasswordHash(A._)).Returns(passwordHash); + + // When + controller.Password(model); + + // Then + A.CallTo(() => cryptoService.GetPasswordHash(A._)).MustHaveHappened(1, Times.Exactly); + var data = controller.TempData.Peek()!; + data.PasswordHash.Should().Be(passwordHash); + } + + [Test] + public void SummaryPost_updates_tempdata_correctly() + { + // Given + const string sampleDelegateNumber = "CR7"; + var data = new DelegateRegistrationByCentreData + { + FirstName = "Test", LastName = "User", Email = "test@mail.com", Centre = 5, JobGroup = 0, + WelcomeEmailDate = new DateTime(2200, 7, 7) + }; + controller.TempData.Set(data); + var model = new SummaryViewModel(); + A.CallTo(() => registrationService.RegisterDelegateByCentre(A._)) + .Returns(sampleDelegateNumber); + + // When + controller.Summary(model); + + // Then + var delegateNumber = (string?)controller.TempData.Peek("delegateNumber"); + var emailSent = (bool)controller.TempData.Peek("emailSent"); + var passwordSet = (bool)controller.TempData.Peek("passwordSet"); + delegateNumber.Should().Be(sampleDelegateNumber); + emailSent.Should().Be(data.ShouldSendEmail); + passwordSet.Should().Be(data.IsPasswordSet); + } } }