Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 53 additions & 3 deletions DigitalLearningSolutions.Data.Tests/Services/UserServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,9 @@ public void UpdateUserAccountDetailsViaDelegateAccount_updates_admin_user_if_fou
delegateUser.FirstName!,
delegateUser.LastName,
delegateUser.EmailAddress!,
delegateUser.AliasId
delegateUser.AliasId,
null,
true
);
var centreAnswersData = new CentreAnswersData(
delegateUser.CentreId,
Expand Down Expand Up @@ -879,7 +881,9 @@ public void UpdateUserAccountDetailsViaDelegateAccount_does_not_update_admin_use
delegateUser.FirstName!,
delegateUser.LastName,
delegateUser.EmailAddress!,
delegateUser.AliasId
delegateUser.AliasId,
null,
true
);
var centreAnswersData = new CentreAnswersData(
delegateUser.CentreId,
Expand Down Expand Up @@ -923,7 +927,9 @@ public void UpdateUserAccountDetailsViaDelegateAccount_updates_name_and_email_on
delegateUser.FirstName!,
delegateUser.LastName,
delegateUser.EmailAddress!,
delegateUser.AliasId
delegateUser.AliasId,
null,
true
);
var centreAnswersData = new CentreAnswersData(
delegateUser.CentreId,
Expand All @@ -950,6 +956,50 @@ public void UpdateUserAccountDetailsViaDelegateAccount_updates_name_and_email_on
).MustHaveHappened();
}

[Test]
public void UpdateUserAccountDetailsViaDelegateAccount_calls_UpdateDelegateProfessionalRegistrationNumber()
{
// Given
const string email = "test@email.com";
const string prn = "PRNNUMBER";
var delegateUser = UserTestHelper.GetDefaultDelegateUser(emailAddress: email);
var secondDelegateUser = UserTestHelper.GetDefaultDelegateUser(3, emailAddress: email);
A.CallTo(() => userDataService.GetDelegateUserById(delegateUser.Id)).Returns(delegateUser);
A.CallTo(() => userDataService.GetDelegateUsersByEmailAddress(email))
.Returns(new List<DelegateUser> { delegateUser, secondDelegateUser });
A.CallTo(() => userDataService.GetAdminUserByEmailAddress(email)).Returns(null);
var editDelegateDetailsData = new EditDelegateDetailsData(
delegateUser.Id,
delegateUser.FirstName!,
delegateUser.LastName,
delegateUser.EmailAddress!,
delegateUser.AliasId,
prn,
true
);
var centreAnswersData = new CentreAnswersData(
delegateUser.CentreId,
delegateUser.JobGroupId,
delegateUser.Answer1,
delegateUser.Answer2,
delegateUser.Answer3,
delegateUser.Answer4,
delegateUser.Answer5,
delegateUser.Answer6
);

// When
userService.UpdateUserAccountDetailsViaDelegateAccount(editDelegateDetailsData, centreAnswersData);

// Then
A.CallTo(
() => userDataService.UpdateDelegateProfessionalRegistrationNumber(
delegateUser.Id,
prn,
true)
).MustHaveHappened();
}

[Test]
public void GetSupervisorsAtCentre_returns_expected_admins()
{
Expand Down
6 changes: 6 additions & 0 deletions DigitalLearningSolutions.Data/Models/User/DelegateUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ public class DelegateUser : User
public string? Answer5 { get; set; }
public string? Answer6 { get; set; }
public string? AliasId { get; set; }
/// <summary>
/// This signifies that the user has either seen the PRN fields themselves
/// or an admin has seen the PRN fields when editing the delegate.
/// This is used to distinguish whether a null ProfessionalRegistrationNumber
/// means they have responded No or haven't answered it yet.
/// </summary>
public bool HasBeenPromptedForPrn { get; set; }
public string? ProfessionalRegistrationNumber { get; set; }
public bool HasDismissedLhLoginWarning { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@ public EditDelegateDetailsData(
string firstName,
string surname,
string email,
string? alias
string? alias,
string? professionalRegNumber,
bool hasBeenPromptedForPrn
) : base(firstName, surname, email)
{
DelegateId = delegateId;
Alias = alias;
ProfessionalRegistrationNumber = professionalRegNumber;
HasBeenPromptedForPrn = hasBeenPromptedForPrn;
}

public int DelegateId { get; set; }
public string? Alias { get; set; }
public string? ProfessionalRegistrationNumber { get; set; }
public bool HasBeenPromptedForPrn { get; set; }
}
}
6 changes: 6 additions & 0 deletions DigitalLearningSolutions.Data/Services/UserService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,12 @@ CentreAnswersData centreAnswersData
editDelegateDetailsData.Email
);

userDataService.UpdateDelegateProfessionalRegistrationNumber(
delegateUser.Id,
editDelegateDetailsData.ProfessionalRegistrationNumber,
editDelegateDetailsData.HasBeenPromptedForPrn
);

groupsService.SynchroniseUserChangesWithGroups(
delegateUser,
editDelegateDetailsData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public void Index_post_returns_view_with_model_error_with_duplicate_email()
{
JobGroupId = 1,
Email = email,
HasProfessionalRegistrationNumber = false,
};
A.CallTo(() => userService.NewEmailAddressIsValid(email, null, DelegateId, A<int>._)).Returns(false);
A.CallTo(() => userService.NewAliasIsValid(A<string>._, DelegateId, A<int>._)).Returns(true);
Expand All @@ -83,7 +84,10 @@ public void Index_post_returns_view_with_model_error_with_duplicate_email()
using (new AssertionScope())
{
result.As<ViewResult>().Model.Should().BeOfType<EditDelegateViewModel>();
AssertModelStateErrorIsExpected(result, "A user with this email address is already registered at this centre");
AssertModelStateErrorIsExpected(
result,
"A user with this email address is already registered at this centre"
);
}
}

Expand All @@ -107,7 +111,37 @@ public void Index_post_returns_view_with_model_error_with_duplicate_alias()
using (new AssertionScope())
{
result.As<ViewResult>().Model.Should().BeOfType<EditDelegateViewModel>();
AssertModelStateErrorIsExpected(result, "A user with this alias ID is already registered at this centre");
AssertModelStateErrorIsExpected(
result,
"A user with this alias ID is already registered at this centre"
);
}
}

[Test]
public void Index_post_returns_view_with_model_error_with_invalid_prn()
{
// Given
var formData = new EditDelegateFormData
{
JobGroupId = 1,
HasProfessionalRegistrationNumber = true,
ProfessionalRegistrationNumber = "!&^£%&*^!%£",
};
A.CallTo(() => userService.NewEmailAddressIsValid(A<string>._, null, DelegateId, A<int>._)).Returns(true);
A.CallTo(() => userService.NewAliasIsValid(A<string>._, DelegateId, A<int>._)).Returns(true);

// When
var result = controller.Index(formData, DelegateId);

// Then
using (new AssertionScope())
{
result.As<ViewResult>().Model.Should().BeOfType<EditDelegateViewModel>();
AssertModelStateErrorIsExpected(
result,
"Invalid professional registration number format - Only alphanumeric characters (a-z, A-Z and 0-9) and hyphens (-) allowed"
);
}
}

Expand All @@ -118,6 +152,7 @@ public void Index_post_calls_userService_and_redirects_with_no_validation_errors
var formData = new EditDelegateFormData
{
JobGroupId = 1,
HasProfessionalRegistrationNumber = false,
};
A.CallTo(() => userService.NewEmailAddressIsValid(A<string>._, null, DelegateId, A<int>._)).Returns(true);
A.CallTo(() => userService.NewAliasIsValid(A<string>._, DelegateId, A<int>._)).Returns(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ public IActionResult Index(EditDelegateFormData formData, int delegateId)
);
}

ProfessionalRegistrationNumberHelper.ValidateProfessionalRegistrationNumber(
ModelState,
formData.HasProfessionalRegistrationNumber,
formData.ProfessionalRegistrationNumber
);

if (!ModelState.IsValid)
{
return ReturnToEditDetailsViewWithErrors(formData, delegateId, centreId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ int centreId
formData.FirstName!,
formData.LastName!,
formData.Email!,
formData.AliasId
formData.AliasId,
formData.HasProfessionalRegistrationNumber == true
? formData.ProfessionalRegistrationNumber
: null,
formData.HasProfessionalRegistrationNumber.HasValue
);

var centreAnswersData = new CentreAnswersData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public class EditDetailsFormData

public string? Answer6 { get; set; }

public string? ProfessionalRegistrationNumber { get; set; }

public bool? HasProfessionalRegistrationNumber { get; set; }

public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!JobGroupId.HasValue)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,5 @@ protected MyAccountEditDetailsFormData(MyAccountEditDetailsFormData formData)
public IFormFile? ProfileImageFile { get; set; }

public bool IsDelegateUser { get; set; }

public string? ProfessionalRegistrationNumber { get; set; }

public bool? HasProfessionalRegistrationNumber { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
using DigitalLearningSolutions.Web.Helpers;
using DigitalLearningSolutions.Web.ViewModels.Common;

public class EditDelegateFormData : EditDetailsFormData, IValidatableObject
public class EditDelegateFormData : EditDetailsFormData, IEditProfessionalRegistrationNumbers, IValidatableObject
{
public EditDelegateFormData() {}

Expand All @@ -28,6 +28,13 @@ public EditDelegateFormData(DelegateUser delegateUser, IEnumerable<(int id, stri
Answer6 = delegateUser.Answer6;

AliasId = delegateUser.AliasId;

ProfessionalRegistrationNumber = delegateUser.ProfessionalRegistrationNumber;
HasProfessionalRegistrationNumber =
ProfessionalRegistrationNumberHelper.GetHasProfessionalRegistrationNumberForView(
delegateUser.HasBeenPromptedForPrn,
delegateUser.ProfessionalRegistrationNumber
);
}

public EditDelegateFormData(EditDelegateFormData formData)
Expand All @@ -43,6 +50,8 @@ public EditDelegateFormData(EditDelegateFormData formData)
Answer5 = formData.Answer5;
Answer6 = formData.Answer6;
AliasId = formData.AliasId;
ProfessionalRegistrationNumber = formData.ProfessionalRegistrationNumber;
HasProfessionalRegistrationNumber = formData.HasProfessionalRegistrationNumber;
}

[MaxLength(250, ErrorMessage = CommonValidationErrorMessages.TooLongLastName)]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@using DigitalLearningSolutions.Web.ViewModels.Common
@using DigitalLearningSolutions.Web.ViewModels.Register
@using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.EditDelegate
@using Microsoft.AspNetCore.Mvc.ModelBinding

@model IEditProfessionalRegistrationNumbers
Expand All @@ -14,17 +15,18 @@
const string professionalRegConditionalId = "professional-reg-conditional-Id";

var isRegisterJourney = Model is LearnerInformationViewModel;
var isEditDelegateByAdmin = Model is EditDelegateViewModel;
}

<div class="nhsuk-form-group @(hasPrnErrorHasOccurred ? " nhsuk-form-group--error" : "" )">
<fieldset class="nhsuk-fieldset" aria-describedby="professional-registration-hint">

<legend class="nhsuk-fieldset__legend nhsuk-fieldset__legend--l">
<div class="nhsuk-label">
Do you have a Professional Registration Number?
Do @(isEditDelegateByAdmin ? "they" : "you") have a Professional Registration Number?
</div>
<div class="nhsuk-hint nhsuk-u-margin-bottom-0" id="professional-registration-hint">
You should have a professional registration number if you are a health professional registered with a professional body such as the NMC, GMC or GDC.
@(isEditDelegateByAdmin ? "They" : "You") should have a professional registration number if @(isEditDelegateByAdmin ? "they" : "you") are a health professional registered with a professional body such as the NMC, GMC or GDC.
@(isRegisterJourney ? "If you don't have it to hand, you can provide it later by visiting My account / Edit details." : "")
</div>
</legend>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
@using Microsoft.Extensions.Configuration
@model EditDelegateViewModel

<link rel="stylesheet" href="@Url.Content("~/css/shared/formElements.css")" asp-append-version="true">

@{
var errorHasOccurred = !ViewData.ModelState.IsValid;
ViewData["Title"] = errorHasOccurred ? "Error: Edit delegate details" : "Edit delegate details";
Expand Down Expand Up @@ -57,6 +59,8 @@
autocomplete=""
hint-text=""
css-class="nhsuk-u-width-one-half" />

<partial name="_EditRegistrationNumber" model="@Model" />
</div>

<vc:select-list asp-for="@nameof(Model.JobGroupId)"
Expand Down