Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FAI-1991 candidate gov auth account recovery #1790

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,85 @@ public async Task Then_If_Candidate_Already_Exists_Then_Details_Are_Returned(
result.Status.Should().Be(candidate.Status);
}
}

[Test, MoqAutoData]
public async Task Then_If_Candidate_Does_Not_Exist_By_Id_But_Exists_By_Email_With_No_GovIdentifier_Then_Details_Are_Returned_And_Identifier_Updated(
CreateCandidateCommand command,
string govUkId,
GetCandidateApiResponse candidate,
PostCandidateApiResponse response,
GetLegacyUserByEmailApiResponse legacyUserByEmailApiResponse,
[Frozen] Mock<ICandidateApiClient<CandidateApiConfiguration>> mockApiClient,
[Frozen] Mock<IFindApprenticeshipLegacyApiClient<FindApprenticeshipLegacyApiConfiguration>> mockLegacyApiClient,
CreateCandidateCommandHandler handler)
{
command.GovUkIdentifier = govUkId;
command.Email = candidate.Email;
candidate.GovUkIdentifier = null;

var expectedGetCandidateRequest = new GetCandidateApiRequest(govUkId);
var expectedGetCandidateByEmailRequest = new GetCandidateByEmailApiRequest(command.Email);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateApiRequest>(r => r.GetUrl == expectedGetCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null!, HttpStatusCode.NotFound, string.Empty));
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateByEmailApiRequest>(r => r.GetUrl == expectedGetCandidateByEmailRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(candidate, HttpStatusCode.OK, string.Empty));
mockApiClient.Setup(x => x.PutWithResponseCode<PutCandidateApiResponse>(
It.Is<PutCandidateApiRequest>(r =>
r.PutUrl.Contains(candidate.Id.ToString())
&& ((PutCandidateApiRequestData)r.Data).GovUkIdentifier == govUkId))).ReturnsAsync(new ApiResponse<PutCandidateApiResponse>(null, HttpStatusCode.OK, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);

using (new AssertionScope())
{
result.GovUkIdentifier.Should().BeEquivalentTo(govUkId);
result.Email.Should().BeEquivalentTo(candidate.Email);
result.FirstName.Should().BeEquivalentTo(candidate.FirstName);
result.LastName.Should().BeEquivalentTo(candidate.LastName);
result.Id.Should().Be(candidate.Id);
result.Status.Should().Be(candidate.Status);
}
mockApiClient.Verify(x => x.PutWithResponseCode<PutCandidateApiResponse>(
It.Is<PutCandidateApiRequest>(r =>
r.PutUrl.Contains(candidate.Id.ToString())
&& ((PutCandidateApiRequestData)r.Data).GovUkIdentifier == govUkId)), Times.Once());
}


[Test, MoqAutoData]
public async Task Then_If_Candidate_Does_Not_Exist_By_Id_But_Exists_By_Email_With_GovIdentifier_Null_Returned(
CreateCandidateCommand command,
string govUkId,
GetCandidateApiResponse candidate,
PostCandidateApiResponse response,
GetLegacyUserByEmailApiResponse legacyUserByEmailApiResponse,
[Frozen] Mock<ICandidateApiClient<CandidateApiConfiguration>> mockApiClient,
[Frozen] Mock<IFindApprenticeshipLegacyApiClient<FindApprenticeshipLegacyApiConfiguration>> mockLegacyApiClient,
CreateCandidateCommandHandler handler)
{
command.GovUkIdentifier = govUkId;
command.Email = candidate.Email;
candidate.GovUkIdentifier = govUkId;

var expectedGetCandidateRequest = new GetCandidateApiRequest(govUkId);
var expectedGetCandidateByEmailRequest = new GetCandidateByEmailApiRequest(command.Email);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateApiRequest>(r => r.GetUrl == expectedGetCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null!, HttpStatusCode.NotFound, string.Empty));
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateByEmailApiRequest>(r => r.GetUrl == expectedGetCandidateByEmailRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(candidate, HttpStatusCode.OK, string.Empty));
mockApiClient.Setup(x => x.PutWithResponseCode<PutCandidateApiResponse>(
It.Is<PutCandidateApiRequest>(r =>
r.PutUrl.Contains(candidate.Id.ToString())
&& ((PutCandidateApiRequestData)r.Data).GovUkIdentifier == govUkId))).ReturnsAsync(new ApiResponse<PutCandidateApiResponse>(null, HttpStatusCode.OK, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);

result.IsEmailAddressMigrated.Should().BeTrue();
}

[Test, MoqAutoData]
public async Task Then_If_Candidate_Already_Exists_And_Email_Is_Different_Then_Updated_And_Details_Are_Returned(
Expand Down Expand Up @@ -106,11 +185,13 @@ public async Task Then_If_Candidate_Email_Address_Has_Already_Been_Migrated_Then
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateApiRequest>(r => r.GetUrl == expectedGetCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var expectedGetMigratedCandidateRequest = new GetCandidateByMigratedEmailApiRequest(command.Email);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateByMigratedEmailApiResponse>(
It.Is<GetCandidateByMigratedEmailApiRequest>(r => r.GetUrl == expectedGetMigratedCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateByMigratedEmailApiResponse>(migratedCandidate, HttpStatusCode.OK, string.Empty));
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);

Expand Down Expand Up @@ -146,6 +227,9 @@ public async Task Then_If_Legacy_User_Exists_Details_Are_Migrated_With_Address(
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateByMigratedEmailApiResponse>(
It.Is<GetCandidateByMigratedEmailApiRequest>(r => r.GetUrl == expectedGetMigratedCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateByMigratedEmailApiResponse>(null, HttpStatusCode.NotFound, string.Empty));
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var expectedRequest = new PostCandidateApiRequest(command.GovUkIdentifier, expectedPostData);

Expand Down Expand Up @@ -245,6 +329,9 @@ public async Task Then_The_Post_Is_Sent_And_If_Legacy_Api_Has_DateOfBirth_As_Dat
.Setup(client => client.Get<GetLegacyUserByEmailApiResponse>(
It.Is<GetLegacyUserByEmailApiRequest>(r => r.GetUrl == legacyGetRequest.GetUrl)))
.ReturnsAsync(legacyUserByEmailApiResponse);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);

Expand Down Expand Up @@ -277,6 +364,9 @@ public async Task And_Api_Returns_Null_Then_Return_Null(
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.Is<GetCandidateApiRequest>(r => r.GetUrl == expectedGetCandidateRequest.GetUrl)))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var expectedGetMigratedCandidateRequest = new GetCandidateByMigratedEmailApiRequest(command.Email);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateByMigratedEmailApiResponse>(
Expand Down Expand Up @@ -335,6 +425,9 @@ public async Task Then_LegacyApi_Returns_Null_The_Post_Is_Sent_And_Data_Returned
.Setup(client => client.Get<GetLegacyUserByEmailApiResponse>(
It.Is<GetLegacyUserByEmailApiRequest>(r => r.GetUrl == legacyGetRequest.GetUrl)))
.ReturnsAsync(() => null);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);

Expand Down Expand Up @@ -393,6 +486,9 @@ public async Task Then_Legacy_Applications_Are_Migrated(
.Setup(client => client.Get<GetLegacyUserByEmailApiResponse>(
It.Is<GetLegacyUserByEmailApiRequest>(r => r.GetUrl == legacyGetRequest.GetUrl)))
.ReturnsAsync(legacyUserByEmailApiResponse);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

await handler.Handle(command, CancellationToken.None);

Expand Down Expand Up @@ -446,6 +542,9 @@ public async Task Then_Legacy_UserDetails_Found_Status_Return_As_InProgress(
.Setup(client => client.Get<GetLegacyUserByEmailApiResponse>(
It.Is<GetLegacyUserByEmailApiRequest>(r => r.GetUrl == legacyGetRequest.GetUrl)))
.ReturnsAsync(legacyUserByEmailApiResponse);
mockApiClient.Setup(x => x.GetWithResponseCode<GetCandidateApiResponse>(
It.IsAny<GetCandidateByEmailApiRequest>()))
.ReturnsAsync(new ApiResponse<GetCandidateApiResponse>(null, HttpStatusCode.NotFound, string.Empty));

var result = await handler.Handle(command, CancellationToken.None);
result.Status.Should().Be(UserStatus.InProgress);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System.Web;
using AutoFixture.NUnit3;
using FluentAssertions;
using NUnit.Framework;
using SFA.DAS.FindAnApprenticeship.InnerApi.CandidateApi.Requests;

namespace SFA.DAS.FindAnApprenticeship.UnitTests.InnerApi.CandidateApi.Requests;

public class WhenBuildingGetCandidateByEmailApiRequest
{
[Test, AutoData]
public void Then_The_Request_Is_Built_Correctly(string emailValue)
{
var email = $"{emailValue}@£$^£@!@{emailValue}.com";

var actual = new GetCandidateByEmailApiRequest(email);

actual.GetUrl.Should().Be($"api/candidates/email/{HttpUtility.UrlEncode(email)}");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,42 @@ await candidateApiClient.GetWithResponseCode<GetCandidateApiResponse>(
};
}

if (existingUser.StatusCode == HttpStatusCode.NotFound)
{
existingUser =
await candidateApiClient.GetWithResponseCode<GetCandidateApiResponse>(
new GetCandidateByEmailApiRequest(request.Email));
if (existingUser.StatusCode != HttpStatusCode.NotFound)
{
if (existingUser.Body.GovUkIdentifier != null)
{
return new CreateCandidateCommandResult
{
IsEmailAddressMigrated = true
};
}

var updateEmailRequest = new PutCandidateApiRequest(existingUser.Body.Id, new PutCandidateApiRequestData
{
GovUkIdentifier = request.GovUkIdentifier
});

await candidateApiClient.PutWithResponseCode<PutCandidateApiResponse>(updateEmailRequest);

return new CreateCandidateCommandResult
{
Id = existingUser.Body.Id,
GovUkIdentifier = request.GovUkIdentifier,
Email = request.Email,
FirstName = existingUser.Body.FirstName,
LastName = existingUser.Body.LastName,
PhoneNumber = existingUser.Body.PhoneNumber,
DateOfBirth = existingUser.Body.DateOfBirth,
Status = existingUser.Body.Status
};
}
}

var userWithMigratedEmail =
await candidateApiClient.GetWithResponseCode<GetCandidateByMigratedEmailApiResponse>(
new GetCandidateByMigratedEmailApiRequest(request.Email));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Web;
using SFA.DAS.SharedOuterApi.Interfaces;

namespace SFA.DAS.FindAnApprenticeship.InnerApi.CandidateApi.Requests;

public class GetCandidateByEmailApiRequest(string email) : IGetApiRequest
{
public string GetUrl => $"api/candidates/email/{HttpUtility.UrlEncode(email)}";
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ public class PutCandidateApiRequestData
public UserStatus? Status { get; set; }
public string MigratedEmail { get; set; }
public Guid? MigratedCandidateId { get; set; }
public string? GovUkIdentifier { get; set; }
}