Skip to content

Commit

Permalink
Amend API responses for TRS alerts data model
Browse files Browse the repository at this point in the history
  • Loading branch information
gunndabad committed Sep 12, 2024
1 parent eddc1ec commit 083a655
Show file tree
Hide file tree
Showing 43 changed files with 628 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ void AddUsing(UsingDirectiveSyntax usingSyntax)

foreach (var (property, propertyType) in referenceGeneratedTypeInfo.Properties)
{
if (excludeMembers.Contains(property.Identifier.ValueText))
{
continue;
}

AddProperty(property, propertyType);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
global using AutoMapper;
global using PostgresModels = TeachingRecordSystem.Core.DataStore.Postgres.Models;
8 changes: 6 additions & 2 deletions TeachingRecordSystem/src/TeachingRecordSystem.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,15 +166,19 @@ public static void Main(string[] args)
{
cfg.AddMaps(typeof(Program).Assembly);
cfg.CreateMap(typeof(Option<>), typeof(Option<>)).ConvertUsing(typeof(OptionMapper<,>));
})
.AddTransient(typeof(OptionMapper<,>));
});

services.Scan(scan =>
{
scan.FromAssemblyOf<Program>()
.AddClasses(filter => filter.InNamespaces("TeachingRecordSystem.Api.V3.Core.Operations").Where(type => type.Name.EndsWith("Handler")))
.AsSelf()
.WithTransientLifetime();

scan.FromAssemblyOf<Program>()
.AddClasses(filter => filter.AssignableTo(typeof(ITypeConverter<,>)))
.AsSelf()
.WithTransientLifetime();
});

services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Program>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace TeachingRecordSystem.Api.V3;

public static class Constants
{
public static IReadOnlyCollection<string> ExposableSanctionCodes { get; } = new[]
public static IReadOnlyCollection<string> LegacyExposableSanctionCodes { get; } = new[]
{
"G1",
"A18",
Expand Down Expand Up @@ -37,7 +37,7 @@ public static class Constants
"A23",
};

public static IReadOnlyCollection<string> ProhibitionSanctionCodes { get; } = new[]
public static IReadOnlyCollection<string> LegacyProhibitionSanctionCodes { get; } = new[]
{
"G1",
"B1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public record FindPersonByLastNameAndDateOfBirthResultItem
public required string MiddleName { get; init; }
public required string LastName { get; init; }
public required IReadOnlyCollection<SanctionInfo> Sanctions { get; init; }
public required IReadOnlyCollection<Alert> Alerts { get; init; }
public required IReadOnlyCollection<NameInfo> PreviousNames { get; init; }
public required InductionStatusInfo? InductionStatus { get; init; }
public required QtsInfo? Qts { get; init; }
Expand Down Expand Up @@ -53,7 +54,7 @@ public async Task<FindPersonByLastNameAndDateOfBirthResult> Handle(FindPersonByL
new GetSanctionsByContactIdsQuery(
contactsById.Keys,
ActiveOnly: true,
new()));
new(dfeta_sanction.Fields.dfeta_StartDate, dfeta_sanction.Fields.dfeta_EndDate)));

var getPreviousNamesTask = crmQueryDispatcher.ExecuteQuery(new GetPreviousNamesByContactIdsQuery(contactsById.Keys));

Expand Down Expand Up @@ -86,13 +87,39 @@ public async Task<FindPersonByLastNameAndDateOfBirthResult> Handle(FindPersonByL
MiddleName = r.ResolveMiddleName(),
LastName = r.ResolveLastName(),
Sanctions = sanctions[r.Id]
.Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode))
.Where(s => Constants.LegacyExposableSanctionCodes.Contains(s.SanctionCode))
.Select(s => new SanctionInfo()
{
Code = s.SanctionCode,
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
})
.AsReadOnly(),
Alerts = await sanctions[r.Id]
.ToAsyncEnumerable()
.SelectAwait(async s =>
{
var alertType = await referenceDataCache.GetAlertTypeByDqtSanctionCode(s.SanctionCode);
var alertCategory = await referenceDataCache.GetAlertCategoryById(alertType.AlertCategoryId);

return new Alert()
{
AlertId = s.Sanction.Id,
AlertType = new()
{
AlertTypeId = alertType.AlertTypeId,
AlertCategory = new()
{
AlertCategoryId = alertCategory.AlertCategoryId,
Name = alertCategory.Name
},
Name = alertType.Name,
DqtSanctionCode = alertType.DqtSanctionCode!
},
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
EndDate = s.Sanction.dfeta_EndDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
};
})
.AsReadOnlyAsync(),
PreviousNames = previousNameHelper.GetFullPreviousNames(previousNames[r.Id], contactsById[r.Id])
.Select(name => new NameInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public record FindPersonsByTrnAndDateOfBirthResultItem
public required string MiddleName { get; init; }
public required string LastName { get; init; }
public required IReadOnlyCollection<SanctionInfo> Sanctions { get; init; }
public required IReadOnlyCollection<Alert> Alerts { get; init; }
public required IReadOnlyCollection<NameInfo> PreviousNames { get; init; }
public required InductionStatusInfo? InductionStatus { get; init; }
public required QtsInfo? Qts { get; init; }
Expand Down Expand Up @@ -60,7 +61,7 @@ public async Task<FindPersonsByTrnAndDateOfBirthResult> Handle(FindPersonsByTrnA
new GetSanctionsByContactIdsQuery(
contactsById.Keys,
ActiveOnly: true,
new()));
new(dfeta_sanction.Fields.dfeta_StartDate, dfeta_sanction.Fields.dfeta_EndDate)));

var getPreviousNamesTask = crmQueryDispatcher.ExecuteQuery(new GetPreviousNamesByContactIdsQuery(contactsById.Keys));

Expand Down Expand Up @@ -93,13 +94,39 @@ public async Task<FindPersonsByTrnAndDateOfBirthResult> Handle(FindPersonsByTrnA
MiddleName = r.ResolveMiddleName(),
LastName = r.ResolveLastName(),
Sanctions = sanctions[r.Id]
.Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode))
.Where(s => Constants.LegacyExposableSanctionCodes.Contains(s.SanctionCode))
.Select(s => new SanctionInfo()
{
Code = s.SanctionCode,
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
})
.AsReadOnly(),
Alerts = await sanctions[r.Id]
.ToAsyncEnumerable()
.SelectAwait(async s =>
{
var alertType = await referenceDataCache.GetAlertTypeByDqtSanctionCode(s.SanctionCode);
var alertCategory = await referenceDataCache.GetAlertCategoryById(alertType.AlertCategoryId);

return new Alert()
{
AlertId = s.Sanction.Id,
AlertType = new()
{
AlertTypeId = alertType.AlertTypeId,
AlertCategory = new()
{
AlertCategoryId = alertCategory.AlertCategoryId,
Name = alertCategory.Name
},
Name = alertType.Name,
DqtSanctionCode = alertType.DqtSanctionCode!
},
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
EndDate = s.Sanction.dfeta_EndDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
};
})
.AsReadOnlyAsync(),
PreviousNames = previousNameHelper.GetFullPreviousNames(previousNames[r.Id], contactsById[r.Id])
.Select(name => new NameInfo()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
using Optional;
using TeachingRecordSystem.Api.V3.Core.SharedModels;
using TeachingRecordSystem.Core.DataStore.Postgres;
using TeachingRecordSystem.Core.DataStore.Postgres.Models;
using TeachingRecordSystem.Core.Dqt;
using TeachingRecordSystem.Core.Dqt.Models;
using TeachingRecordSystem.Core.Dqt.Queries;

namespace TeachingRecordSystem.Api.V3.Core.Operations;

public record GetPersonCommand(string Trn, GetPersonCommandIncludes Include, DateOnly? DateOfBirth);
public record GetPersonCommand(string Trn, GetPersonCommandIncludes Include, DateOnly? DateOfBirth, bool ApplyLegacyAlertsBehavior);

[Flags]
public enum GetPersonCommandIncludes
Expand Down Expand Up @@ -47,7 +46,7 @@ public record GetPersonResult
public required Option<IReadOnlyCollection<GetPersonResultMandatoryQualification>> MandatoryQualifications { get; init; }
public required Option<IReadOnlyCollection<GetPersonResultHigherEducationQualification>> HigherEducationQualifications { get; init; }
public required Option<IReadOnlyCollection<SanctionInfo>> Sanctions { get; init; }
public required Option<IReadOnlyCollection<AlertInfo>> Alerts { get; init; }
public required Option<IReadOnlyCollection<Alert>> Alerts { get; init; }
public required Option<IReadOnlyCollection<NameInfo>> PreviousNames { get; init; }
public required Option<bool> AllowIdSignInWithProhibitions { get; init; }
}
Expand Down Expand Up @@ -392,7 +391,7 @@ async Task<SanctionResult[]> GetSanctions()
default,
Sanctions = command.Include.HasFlag(GetPersonCommandIncludes.Sanctions) ?
Option.Some((await getSanctionsTask!)
.Where(s => Constants.ExposableSanctionCodes.Contains(s.SanctionCode))
.Where(s => Constants.LegacyExposableSanctionCodes.Contains(s.SanctionCode))
.Where(s => s.Sanction.dfeta_EndDate is null && s.Sanction.dfeta_Spent != true)
.Select(s => new SanctionInfo()
{
Expand All @@ -402,16 +401,34 @@ async Task<SanctionResult[]> GetSanctions()
.AsReadOnly()) :
default,
Alerts = command.Include.HasFlag(GetPersonCommandIncludes.Alerts) ?
Option.Some((await getSanctionsTask!)
.Where(s => Constants.ProhibitionSanctionCodes.Contains(s.SanctionCode))
.Select(s => new AlertInfo()
Option.Some(await (await getSanctionsTask!)
.ToAsyncEnumerable()
// The Legacy behavior is to only return prohibition-type alerts
.Where(s => !command.ApplyLegacyAlertsBehavior || Constants.LegacyProhibitionSanctionCodes.Contains(s.SanctionCode))
.SelectAwait(async s =>
{
AlertType = SharedModels.AlertType.Prohibition,
DqtSanctionCode = s.SanctionCode,
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
EndDate = s.Sanction.dfeta_EndDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
var alertType = await referenceDataCache.GetAlertTypeByDqtSanctionCode(s.SanctionCode);
var alertCategory = await referenceDataCache.GetAlertCategoryById(alertType.AlertCategoryId);

return new Alert()
{
AlertId = s.Sanction.Id,
AlertType = new()
{
AlertTypeId = alertType.AlertTypeId,
AlertCategory = new()
{
AlertCategoryId = alertCategory.AlertCategoryId,
Name = alertCategory.Name
},
Name = alertType.Name,
DqtSanctionCode = alertType.DqtSanctionCode!
},
StartDate = s.Sanction.dfeta_StartDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true),
EndDate = s.Sanction.dfeta_EndDate?.ToDateOnlyWithDqtBstFix(isLocalTime: true)
};
})
.AsReadOnly()) :
.AsReadOnlyAsync()) :
default,
PreviousNames = command.Include.HasFlag(GetPersonCommandIncludes.PreviousNames) ?
Option.Some(previousNames.Select(n => n).AsReadOnly()) :
Expand Down Expand Up @@ -576,7 +593,7 @@ private static NpqQualificationType MapNpqQualificationType(dfeta_qualification_
_ => throw new ArgumentException($"Unrecognized qualification type: '{qualificationType}'.", nameof(qualificationType))
};

private static IReadOnlyCollection<GetPersonResultMandatoryQualification> MapMandatoryQualifications(MandatoryQualification[] qualifications) =>
private static IReadOnlyCollection<GetPersonResultMandatoryQualification> MapMandatoryQualifications(PostgresModels.MandatoryQualification[] qualifications) =>
qualifications
.Where(q => q.EndDate.HasValue && q.Specialism.HasValue)
.Select(mq => new GetPersonResultMandatoryQualification()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
namespace TeachingRecordSystem.Api.V3.Core.SharedModels;

public record AlertInfo
public record Alert
{
public required Guid AlertId { get; init; }
public required AlertType AlertType { get; init; }
public required string DqtSanctionCode { get; init; }
public required DateOnly? StartDate { get; init; }
public required DateOnly? EndDate { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace TeachingRecordSystem.Api.V3.Core.SharedModels;

public record AlertCategory
{
public required Guid AlertCategoryId { get; init; }
public required string Name { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace TeachingRecordSystem.Api.V3.Core.SharedModels;

public enum AlertType
public record AlertType
{
Prohibition,
// Only exposing Prohibitions for now
public required Guid AlertTypeId { get; init; }
public required AlertCategory AlertCategory { get; init; }
public required string Name { get; init; }
public required string DqtSanctionCode { get; init; }
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
using TeachingRecordSystem.Api.V3.Core.SharedModels;

namespace TeachingRecordSystem.Api.V3.V20240101.ApiModels;

[AutoMap(typeof(Core.SharedModels.AlertInfo))]
[AutoMap(typeof(Alert), TypeConverter = typeof(AlertInfoTypeConverter))]
public record AlertInfo
{
public required AlertType AlertType { get; init; }
public required string DqtSanctionCode { get; init; }
public required DateOnly? StartDate { get; init; }
public required DateOnly? EndDate { get; init; }
}

public class AlertInfoTypeConverter : ITypeConverter<Alert, AlertInfo>
{
public AlertInfo Convert(Alert source, AlertInfo destination, ResolutionContext context) =>
new()
{
AlertType = AlertType.Prohibition,
DqtSanctionCode = source.AlertType.DqtSanctionCode,
StartDate = source.StartDate,
EndDate = source.EndDate,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
trn,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
DateOfBirth: null);
DateOfBirth: null,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
trn,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
DateOfBirth: null);
DateOfBirth: null,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
trn,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
DateOfBirth: null);
DateOfBirth: null,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
trn,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
dateOfBirth);
dateOfBirth,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
Trn: User.FindFirstValue("trn")!,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
DateOfBirth: null);
DateOfBirth: null,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);
var response = mapper.Map<GetPersonResponse?>(result);
return response is null ? Forbid() : Ok(result);
return response is null ? Forbid() : Ok(response);
}

[HttpPost("name-changes")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public async Task<IActionResult> Get(
var command = new GetPersonCommand(
trn,
include is not null ? (GetPersonCommandIncludes)include : GetPersonCommandIncludes.None,
dateOfBirth);
dateOfBirth,
ApplyLegacyAlertsBehavior: true);

var result = await handler.Handle(command);

Expand All @@ -51,7 +52,7 @@ public async Task<IActionResult> Get(
[ProducesResponseType(typeof(FindPersonResponse), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
[Authorize(Policy = AuthorizationPolicies.ApiKey, Roles = ApiRoles.GetPerson)]
public async Task<IActionResult> FindTeachers(
public async Task<IActionResult> FindPersons(
FindPersonRequest request,
[FromServices] FindPersonByLastNameAndDateOfBirthHandler handler)
{
Expand Down
Loading

0 comments on commit 083a655

Please sign in to comment.