-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
255 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
...dSystem/src/TeachingRecordSystem.Api/V3/Core/Operations/FindPersonsByTrnAndDateOfBirth.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
using System.Collections.Immutable; | ||
using Microsoft.Xrm.Sdk.Query; | ||
using TeachingRecordSystem.Api.V3.Core.SharedModels; | ||
using TeachingRecordSystem.Core.Dqt; | ||
using TeachingRecordSystem.Core.Dqt.Models; | ||
using TeachingRecordSystem.Core.Dqt.Queries; | ||
|
||
namespace TeachingRecordSystem.Api.V3.Core.Operations; | ||
|
||
public record FindPersonsByTrnAndDateOfBirthCommand(IEnumerable<(string Trn, DateOnly DateOfBirth)> Persons); | ||
|
||
public record FindPersonsByTrnAndDateOfBirthResult(int Total, IReadOnlyCollection<FindPersonsByTrnAndDateOfBirthResultItem> Items); | ||
|
||
public record FindPersonsByTrnAndDateOfBirthResultItem | ||
{ | ||
public required string Trn { get; init; } | ||
public required DateOnly DateOfBirth { get; init; } | ||
public required string FirstName { get; init; } | ||
public required string MiddleName { get; init; } | ||
public required string LastName { get; init; } | ||
public required IReadOnlyCollection<SanctionInfo> Sanctions { get; init; } | ||
public required IReadOnlyCollection<NameInfo> PreviousNames { get; init; } | ||
} | ||
|
||
public class FindPersonsByTrnAndDateOfBirthHandler(ICrmQueryDispatcher crmQueryDispatcher, PreviousNameHelper previousNameHelper) | ||
{ | ||
public async Task<FindPersonsByTrnAndDateOfBirthResult> Handle(FindPersonsByTrnAndDateOfBirthCommand command) | ||
{ | ||
var contacts = await crmQueryDispatcher.ExecuteQuery( | ||
new GetActiveContactsByTrnsQuery( | ||
command.Persons.Select(p => p.Trn), | ||
new ColumnSet( | ||
Contact.Fields.dfeta_TRN, | ||
Contact.Fields.BirthDate, | ||
Contact.Fields.FirstName, | ||
Contact.Fields.MiddleName, | ||
Contact.Fields.LastName, | ||
Contact.Fields.dfeta_StatedFirstName, | ||
Contact.Fields.dfeta_StatedMiddleName, | ||
Contact.Fields.dfeta_StatedLastName))); | ||
|
||
// Remove any results where the request DOB doesn't match the contact's DOB | ||
// (we can't easily do this in the query itself). | ||
var matched = contacts | ||
.Where(kvp => kvp.Value is not null) | ||
.Where(kvp => command.Persons.Any(p => p.Trn == kvp.Key && p.DateOfBirth == kvp.Value!.BirthDate?.ToDateOnlyWithDqtBstFix(isLocalTime: false))) | ||
.Select(kvp => kvp.Value!) | ||
.ToArray(); | ||
|
||
var contactsById = matched.ToDictionary(c => c.Id, c => c); | ||
|
||
var sanctions = await crmQueryDispatcher.ExecuteQuery( | ||
new GetSanctionsByContactIdsQuery( | ||
contactsById.Keys, | ||
ActiveOnly: true, | ||
new())); | ||
|
||
var previousNames = (await crmQueryDispatcher.ExecuteQuery(new GetPreviousNamesByContactIdsQuery(contactsById.Keys))) | ||
.ToDictionary( | ||
kvp => kvp.Key, | ||
kvp => previousNameHelper.GetFullPreviousNames(kvp.Value, contactsById[kvp.Key])); | ||
|
||
return new FindPersonsByTrnAndDateOfBirthResult( | ||
Total: matched.Length, | ||
Items: matched.Select(r => new FindPersonsByTrnAndDateOfBirthResultItem() | ||
{ | ||
Trn = r.dfeta_TRN, | ||
DateOfBirth = r.BirthDate!.Value.ToDateOnlyWithDqtBstFix(isLocalTime: false), | ||
FirstName = r.ResolveFirstName(), | ||
MiddleName = r.ResolveMiddleName(), | ||
LastName = r.ResolveLastName(), | ||
Sanctions = sanctions[r.Id] | ||
.Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode)) | ||
.Select(s => new SanctionInfo() | ||
{ | ||
Code = s.SanctionCode, | ||
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true) | ||
}) | ||
.AsReadOnly(), | ||
PreviousNames = previousNames[r.Id] | ||
.Select(name => new NameInfo() | ||
{ | ||
FirstName = name.FirstName, | ||
MiddleName = name.MiddleName, | ||
LastName = name.LastName | ||
}) | ||
.AsReadOnly() | ||
}) | ||
.OrderBy(c => c.Trn) | ||
.AsReadOnly()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
...ngRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Controllers/PersonsController.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
using Microsoft.AspNetCore.Authorization; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Swashbuckle.AspNetCore.Annotations; | ||
using TeachingRecordSystem.Api.Infrastructure.Security; | ||
using TeachingRecordSystem.Api.V3.Core.Operations; | ||
using TeachingRecordSystem.Api.V3.V20240814.Requests; | ||
using TeachingRecordSystem.Api.V3.V20240814.Responses; | ||
|
||
namespace TeachingRecordSystem.Api.V3.V20240814.Controllers; | ||
|
||
[Route("persons")] | ||
public class PersonsController(IMapper mapper) : ControllerBase | ||
{ | ||
[HttpPost("find")] | ||
[SwaggerOperation( | ||
OperationId = "FindPersons", | ||
Summary = "Find persons", | ||
Description = "Finds persons matching the specified criteria.")] | ||
[ProducesResponseType(typeof(FindPersonsResponse), StatusCodes.Status200OK)] | ||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] | ||
[Authorize(Policy = AuthorizationPolicies.GetPerson)] | ||
public async Task<IActionResult> FindTeachers( | ||
[FromBody] FindPersonsRequest request, | ||
[FromServices] FindPersonsByTrnAndDateOfBirthHandler handler) | ||
{ | ||
var command = new FindPersonsByTrnAndDateOfBirthCommand(request.Persons.Select(p => (p.Trn, p.DateOfBirth))); | ||
var result = await handler.Handle(command); | ||
var response = mapper.Map<FindPersonsResponse>(result); | ||
return Ok(response); | ||
} | ||
|
||
[HttpGet("")] | ||
[SwaggerOperation( | ||
OperationId = "FindPerson", | ||
Summary = "Find person", | ||
Description = "Finds a person matching the specified criteria.")] | ||
[ProducesResponseType(typeof(FindPersonResponse), StatusCodes.Status200OK)] | ||
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] | ||
[Authorize(Policy = AuthorizationPolicies.GetPerson)] | ||
public async Task<IActionResult> FindTeachers( | ||
FindPersonRequest request, | ||
[FromServices] FindPersonByLastNameAndDateOfBirthHandler handler) | ||
{ | ||
var command = new FindPersonByLastNameAndDateOfBirthCommand(request.LastName!, request.DateOfBirth!.Value); | ||
var result = await handler.Handle(command); | ||
|
||
var response = new FindPersonResponse() | ||
{ | ||
Total = result.Total, | ||
Query = request, | ||
Results = result.Items.Select(mapper.Map<FindPersonResponseResult>).AsReadOnly() | ||
}; | ||
|
||
return Ok(response); | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
TeachingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Requests/FindPersonRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace TeachingRecordSystem.Api.V3.V20240814.Requests; | ||
|
||
public record FindPersonRequest | ||
{ | ||
[FromQuery(Name = "findBy")] | ||
public FindPersonFindBy FindBy { get; init; } | ||
[FromQuery(Name = "lastName")] | ||
public string? LastName { get; init; } | ||
[FromQuery(Name = "dateOfBirth")] | ||
public DateOnly? DateOfBirth { get; init; } | ||
} | ||
|
||
public enum FindPersonFindBy | ||
{ | ||
LastNameAndDateOfBirth = 1 | ||
} |
2 changes: 1 addition & 1 deletion
2
...i/V3/VNext/Requests/FindPersonsRequest.cs → .../V20240814/Requests/FindPersonsRequest.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
...ingRecordSystem/src/TeachingRecordSystem.Api/V3/V20240814/Responses/FindPersonResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using TeachingRecordSystem.Api.V3.Core.Operations; | ||
using TeachingRecordSystem.Api.V3.V20240101.ApiModels; | ||
using TeachingRecordSystem.Api.V3.V20240814.Requests; | ||
|
||
namespace TeachingRecordSystem.Api.V3.V20240814.Responses; | ||
|
||
public record FindPersonResponse | ||
{ | ||
public required int Total { get; init; } | ||
public required FindPersonRequest Query { get; init; } | ||
public required IReadOnlyCollection<FindPersonResponseResult> Results { get; init; } | ||
} | ||
|
||
[AutoMap(typeof(FindPersonByLastNameAndDateOfBirthResultItem))] | ||
public record FindPersonResponseResult | ||
{ | ||
public required string Trn { get; init; } | ||
public required DateOnly DateOfBirth { get; init; } | ||
public required string FirstName { get; init; } | ||
public required string MiddleName { get; init; } | ||
public required string LastName { get; init; } | ||
public required IReadOnlyCollection<SanctionInfo> Sanctions { get; init; } | ||
public required IReadOnlyCollection<NameInfo> PreviousNames { get; init; } | ||
} |
7 changes: 6 additions & 1 deletion
7
...V3/VNext/Responses/FindPersonsResponse.cs → ...20240814/Responses/FindPersonsResponse.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 7 additions & 6 deletions
13
TeachingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Models/PreviousNameHelper.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
...ingRecordSystem/src/TeachingRecordSystem.Core/Dqt/Queries/GetActiveContactsByTrnsQuery.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
using Microsoft.Xrm.Sdk.Query; | ||
|
||
namespace TeachingRecordSystem.Core.Dqt.Queries; | ||
|
||
public record GetActiveContactsByTrnsQuery(IEnumerable<string> Trns, ColumnSet ColumnSet) : | ||
ICrmQuery<IDictionary<string, Contact?>>; |
33 changes: 33 additions & 0 deletions
33
...dSystem/src/TeachingRecordSystem.Core/Dqt/QueryHandlers/GetActiveContactsByTrnsHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using AngleSharp.Common; | ||
using Microsoft.PowerPlatform.Dataverse.Client; | ||
using Microsoft.Xrm.Sdk.Query; | ||
using TeachingRecordSystem.Core.Dqt.Queries; | ||
|
||
namespace TeachingRecordSystem.Core.Dqt.QueryHandlers; | ||
|
||
public class GetActiveContactsByTrnsHandler : | ||
ICrmQueryHandler<GetActiveContactsByTrnsQuery, IDictionary<string, Contact?>> | ||
{ | ||
public async Task<IDictionary<string, Contact?>> Execute( | ||
GetActiveContactsByTrnsQuery query, | ||
IOrganizationServiceAsync organizationService) | ||
{ | ||
var queryExpression = new QueryExpression(Contact.EntityLogicalName) | ||
{ | ||
ColumnSet = query.ColumnSet, | ||
Criteria = new FilterExpression(LogicalOperator.And) | ||
{ | ||
Conditions = | ||
{ | ||
new ConditionExpression(Contact.Fields.StateCode, ConditionOperator.Equal, (int)ContactState.Active), | ||
new ConditionExpression(Contact.Fields.dfeta_TRN, ConditionOperator.In, query.Trns.ToArray()) | ||
} | ||
} | ||
}; | ||
|
||
var response = await organizationService.RetrieveMultipleAsync(queryExpression); | ||
var contacts = response.Entities.Select(e => e.ToEntity<Contact>()).ToDictionary(c => c.dfeta_TRN, c => c); | ||
|
||
return query.Trns.ToDictionary(trn => trn, trn => contacts.GetValueOrDefault(trn)); | ||
} | ||
} |
Oops, something went wrong.